mpark / variant

C++17 `std::variant` for C++11/14/17
https://mpark.github.io/variant
Boost Software License 1.0
659 stars 88 forks source link

vector of move-only type doesn't work as element #45

Closed frankheckenbach closed 6 years ago

frankheckenbach commented 6 years ago

Apparently a vector of a move-only type doesn't seem to work as an element type of this variant implementation. I don't quite understand why, as unique_ptr by itself does work, and as I understand it a vector of this type should be moveable (and not copyable) just like unique_ptr itself.

E.g., using gcc 7.3.0 with "--std=c++17" (also with gcc 6.3.0), the following code does not compile:

#include <vector>
#include <memory>
#include "variant.hpp"

int main ()
{
  mpark::variant <std::vector <std::unique_ptr <int>>> foo;
}

In file included from /usr/local/gcc-7/include/c++/7.3.0/vector:62:0,
                 from variant-master/include/mpark/test.cpp:1:
/usr/local/gcc-7/include/c++/7.3.0/bits/stl_construct.h: In instantiation of 'void std::_Construct(_T1*, _Args&& ...) [with _T1 = std::unique_ptr<int>; _Args = {const std::unique_ptr<int, std::default_delete<int> >&}]':
/usr/local/gcc-7/include/c++/7.3.0/bits/stl_uninitialized.h:83:18:   required from 'static _ForwardIterator std::__uninitialized_copy<_TrivialValueTypes>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; bool _TrivialValueTypes = false]'
/usr/local/gcc-7/include/c++/7.3.0/bits/stl_uninitialized.h:134:15:   required from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*]'
/usr/local/gcc-7/include/c++/7.3.0/bits/stl_uninitialized.h:289:37:   required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; _Tp = std::unique_ptr<int>]'
/usr/local/gcc-7/include/c++/7.3.0/bits/stl_vector.h:331:31:   required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<int>; _Alloc = std::allocator<std::unique_ptr<int> >]'
/usr/local/gcc-7/include/c++/7.3.0/type_traits:1406:12:   required from 'struct std::is_trivially_copy_constructible<std::vector<std::unique_ptr<int> > >'
variant-master/include/mpark/variant.hpp:377:18:   required from 'constexpr mpark::detail::Trait mpark::detail::trait() [with T = std::vector<std::unique_ptr<int> >; IsTriviallyAvailable = std::is_trivially_copy_constructible; IsAvailable = std::is_copy_constructible]'
variant-master/include/mpark/variant.hpp:416:57:   required from 'constexpr const mpark::detail::Trait mpark::detail::traits<std::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > > >::copy_constructible_trait'
variant-master/include/mpark/variant.hpp:424:23:   required from 'constexpr const mpark::detail::Trait mpark::detail::traits<std::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > > >::copy_assignable_trait'
variant-master/include/mpark/variant.hpp:1205:11:   required from 'class mpark::detail::impl<std::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > > >'
variant-master/include/mpark/variant.hpp:1504:25:   required from 'class mpark::variant<std::vector<std::unique_ptr<int, std::default_delete<int> >, std::allocator<std::unique_ptr<int, std::default_delete<int> > > > >'
variant-master/include/mpark/test.cpp:7:56:   required from here
/usr/local/gcc-7/include/c++/7.3.0/bits/stl_construct.h:75:7: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]'
     { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/local/gcc-7/include/c++/7.3.0/memory:80:0,
                 from variant-master/include/mpark/test.cpp:2:
/usr/local/gcc-7/include/c++/7.3.0/bits/unique_ptr.h:388:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~

Whereas the same code with std::variant does compile (gcc 7.3.0 only; 6.3.0 doesn't yet have std::variant):

#include <vector>
#include <memory>
#include <variant>

int main ()
{
  std::variant <std::vector <std::unique_ptr <int>>> foo;
}

Any ideas? (Or workarounds?)

frankheckenbach commented 6 years ago

Traced it down a bit, seems to be a consequence of this GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654 So probably nothing this code can do about it. (Well, not easily; apparently GCC's std::variant doesn't hit the bug, but its implementation is probably too different.)