7

I have this piece of code that works really good in GCC7.2, clang 7 and MSVC, but not in GCC 8.0. Apparently, it deals with the copy constructor...

#include <iostream>
#include <variant>
#include <memory>
#include <type_traits>

struct EmptyTree{};

struct Node {
    using node = std::unique_ptr<Node>;
    using Tree = std::variant<node, EmptyTree>;

    Node(int v) : value(v){}
    template<typename left, typename right>
    Node(int v, left &&l, right &&r) : value(v), left(std::move(l)), right(std::move(r)){}
    int value;
    Tree left = EmptyTree{};
    Tree right = EmptyTree{};
};

using Tree = Node::Tree;

auto make_node(int v) {
    return std::make_unique<Node>(v);
}

int main() {
    Tree a;
    a = Tree{make_node(5)};
    return 0;
}

The wandbox to test the code https://wandbox.org/permlink/Z8yXCen0fqbV3PDD

Is it a bug of Gcc 8 or a bug in my code?

I got this error :

In file included from prog.cc:2:
/opt/wandbox/gcc-head/include/c++/8.0.1/variant: In instantiation of 'void std::__detail::__variant::__erased_assign(void*, void*) [with _Lhs = std::unique_ptr<Node>&; _Rhs = const std::unique_ptr<Node>&]':
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:607:27:   required from 'std::__detail::__variant::_Move_assign_base<<anonymous>, _Types>& std::__detail::__variant::_Move_assign_base<<anonymous>, _Types>::operator=(std::__detail::__variant::_Move_assign_base<<anonymous>, _Types>&&) [with bool <anonymous> = false; _Types = {std::unique_ptr<Node, std::default_delete<Node> >, EmptyTree}]'
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:648:12:   required from here
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:258:42: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Node; _Dp = std::default_delete<Node>]'
       __variant::__ref_cast<_Lhs>(__lhs) = __variant::__ref_cast<_Rhs>(__rhs);
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /opt/wandbox/gcc-head/include/c++/8.0.1/memory:80,
                 from prog.cc:3:
/opt/wandbox/gcc-head/include/c++/8.0.1/bits/unique_ptr.h:395:19: note: declared here
       unique_ptr& operator=(const unique_ptr&) = delete;
                   ^~~~~~~~
In file included from prog.cc:2:
/opt/wandbox/gcc-head/include/c++/8.0.1/variant: In instantiation of 'void std::__detail::__variant::__erased_ctor(void*, void*) [with _Lhs = std::unique_ptr<Node>&; _Rhs = const std::unique_ptr<Node>&]':
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:468:30:   required from 'std::__detail::__variant::_Copy_ctor_base<<anonymous>, _Types>::_Copy_ctor_base(const std::__detail::__variant::_Copy_ctor_base<<anonymous>, _Types>&) [with bool <anonymous> = false; _Types = {std::unique_ptr<Node, std::default_delete<Node> >, EmptyTree}]'
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:509:7:   required from 'std::__detail::__variant::_Move_assign_base<<anonymous>, _Types>& std::__detail::__variant::_Move_assign_base<<anonymous>, _Types>::operator=(std::__detail::__variant::_Move_assign_base<<anonymous>, _Types>&&) [with bool <anonymous> = false; _Types = {std::unique_ptr<Node, std::default_delete<Node> >, EmptyTree}]'
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:648:12:   required from here
/opt/wandbox/gcc-head/include/c++/8.0.1/variant:246:7: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Node; _Dp = std::default_delete<Node>]'
       ::new (__lhs) _Type(__variant::__ref_cast<_Rhs>(__rhs));
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /opt/wandbox/gcc-head/include/c++/8.0.1/memory:80,
                 from prog.cc:3:
/opt/wandbox/gcc-head/include/c++/8.0.1/bits/unique_ptr.h:394:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~
Antoine Morrier
  • 3,930
  • 16
  • 37
  • "Doesn't work" how *exactly*? – Yakk - Adam Nevraumont Apr 03 '18 at 21:48
  • it does not compile – Antoine Morrier Apr 03 '18 at 21:49
  • 1
    Bug, probably caused by copypasta. – T.C. Apr 03 '18 at 21:55
  • 1
    It's really ugly to have a template parameter on your constructor named `left` and `right`, as well as class attributes named `left` and `right`. The standard probably allows it, but seriously, don't do that. Make the template parameter types `LEFT` and `RIGHT` or something to make the distinction clear. Also, given you're receiving forwarding references, thanks to the templating, shouldn't you be using `std::forward`, not `std::move` when initializing the `left` and `right` members? – ShadowRanger Apr 03 '18 at 21:58
  • 9
    Reported as https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85183 – T.C. Apr 03 '18 at 22:10
  • @ShadowRanger Yes it is right, I will rename them now, it was just for the example :)., however, I do not want perfect forwarding here because I want move it either it is an lvalue and rvalue – Antoine Morrier Apr 03 '18 at 22:16
  • 1
    Please don't name template parameters `AS_MACROS`, @ShadowRanger. Rather use `left_type` and `right_type`. – Ulrich Eckhardt Apr 04 '18 at 04:34

0 Answers0