[variant] compatibility with move-constructible objects

I have the following rough sequence of typedefs: struct empty {}; typedef std::unique_ptr<foo> foo_ptr; typedef std::unique_ptr<bar> bar_ptr; typedef std::vector<foo_ptr> foo_ptr_vec; typedef std::vector<bar_ptr> bar_ptr_vec; typedef std::variant<empty, foo_ptr_vec, bar_ptr_vec> my_variant; I then declare an instance of my_variant in a class, and make the class moveable and noncopyable. class my_class { my_class(const my_class&); my_class& my_class(const my_class&); my_variant v_; public: my_class(my_class&& other) : v_(std::move(other.v_)) { } }; I cannot get this to compile under MSVC 10 and boost 1.42. In theory I don't see why this shouldn't be ok. Even though the objects are not copy-constructible due to unique_ptr, they are move constructible. The errors are quite long, but you can see it's trying to invoke vector::operator= from within the variant code. Is this just a technical limitation of variant, or a bug? 1> behavior_collection.cpp 1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xutility(2144): error C2248: 'behavior_collection::behavior_impl<Output>::operator =' : cannot access private member declared in class 'behavior_collection::behavior_impl<Output>' 1> with 1> [ 1> Output=kinematic_output 1> ] 1> c:\users\zach\documents\visual studio 2010\projects\dxdemo\dxdemo\behavior_collection.h(15) : see declaration of 'behavior_collection::behavior_impl<Output>::operator =' 1> with 1> [ 1> Output=kinematic_output 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xutility(2165) : see reference to function template instantiation '_OutIt std::_Copy_impl<_InIt,_OutIt>(_InIt,_InIt,_OutIt,std::_Nonscalar_ptr_iterator_tag)' being compiled 1> with 1> [ 1> _OutIt=behavior_collection::behavior_impl<kinematic_output> *, 1> _InIt=behavior_collection::behavior_impl<kinematic_output> * 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector(719) : see reference to function template instantiation '_OutIt std::_Copy_impl<behavior_collection::behavior_impl<Output>*,behavior_collection::behavior_impl<Output>*>(_InIt,_InIt,_OutIt)' being compiled 1> with 1> [ 1> _OutIt=behavior_collection::behavior_impl<kinematic_output> *, 1> Output=kinematic_output, 1> _InIt=behavior_collection::behavior_impl<kinematic_output> * 1> ] 1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector(709) : while compiling class template member function 'std::vector<_Ty> &std::vector<_Ty>::operator =(const std::vector<_Ty> &)' 1> with 1> [ 1> _Ty=behavior_collection::behavior_impl<kinematic_output> 1> ] 1> C:\dev\boost\1.42.0\boost/type_traits/is_pod.hpp(34) : see reference to class template instantiation 'std::vector<_Ty>' being compiled 1> with 1> [ 1> _Ty=behavior_collection::behavior_impl<kinematic_output> 1> ] 1> C:\dev\boost\1.42.0\boost/type_traits/is_pod.hpp(129) : see reference to class template instantiation 'boost::detail::is_pod_impl<T>' being compiled 1> with 1> [ 1> T=std::vector<behavior_collection::behavior_impl<kinematic_output>> 1> ] 1> C:\dev\boost\1.42.0\boost/type_traits/has_trivial_constructor.hpp(27) : see reference to class template instantiation 'boost::is_pod<T>' being compiled 1> with 1> [ 1> T=std::vector<behavior_collection::behavior_impl<kinematic_output>> 1> ] 1> C:\dev\boost\1.42.0\boost/type_traits/has_trivial_constructor.hpp(36) : see reference to class template instantiation 'boost::detail::has_trivial_ctor_impl<T>' being compiled 1> with 1> [ 1> T=std::vector<behavior_collection::behavior_impl<kinematic_output>> 1> ] 1> C:\dev\boost\1.42.0\boost/type_traits/has_nothrow_constructor.hpp(23) : see reference to class template instantiation 'boost::has_trivial_constructor<T>' being compiled 1> with 1> [ 1> T=std::vector<behavior_collection::behavior_impl<kinematic_output>> 1> ] 1> C:\dev\boost\1.42.0\boost/type_traits/has_nothrow_constructor.hpp(32) : see reference to class template instantiation 'boost::detail::has_nothrow_constructor_imp<T>' being compiled 1> with 1> [ 1> T=std::vector<behavior_collection::behavior_impl<kinematic_output>> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/not.hpp(41) : see reference to class template instantiation 'boost::has_nothrow_constructor<T>' being compiled 1> with 1> [ 1> T=std::vector<behavior_collection::behavior_impl<kinematic_output>> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/aux_/preprocessed/plain/and.hpp(25) : see reference to class template instantiation 'boost::mpl::not_<T>' being compiled 1> with 1> [ 1> T=boost::has_nothrow_constructor<std::vector<behavior_collection::behavior_impl<kinematic_output>>> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/aux_/preprocessed/plain/and.hpp(55) : see reference to class template instantiation 'boost::mpl::aux::and_impl<C_,T1,T2,T3,T4>' being compiled 1> with 1> [ 1> C_=true, 1> T1=boost::mpl::apply1<boost::mpl::protect<boost::detail::variant::find_fallback_type_pred>,boost::mpl::l_iter<boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>>>, 1> T2=boost::mpl::true_, 1> T3=boost::mpl::true_, 1> T4=boost::mpl::true_ 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/iter_fold_if.hpp(46) : see reference to class template instantiation 'boost::mpl::and_<T1,T2>' being compiled 1> with 1> [ 1> T1=boost::mpl::not_<boost::is_same<boost::mpl::l_iter<boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>>,boost::mpl::l_iter<boost::mpl::l_end>>>, 1> T2=boost::mpl::apply1<boost::mpl::protect<boost::detail::variant::find_fallback_type_pred>,boost::mpl::l_iter<boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>>> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/aux_/preprocessed/plain/apply_wrap.hpp(49) : see reference to class template instantiation 'boost::mpl::aux::iter_fold_if_pred<Predicate,LastIterator>::apply<State,Iterator>' being compiled 1> with 1> [ 1> Predicate=boost::mpl::protect<boost::detail::variant::find_fallback_type_pred>, 1> LastIterator=boost::mpl::l_iter<boost::mpl::l_end>, 1> State=boost::mpl::int_<1>, 1> Iterator=boost::mpl::l_iter<boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/aux_/preprocessed/plain/apply.hpp(63) : see reference to class template instantiation 'boost::mpl::apply_wrap2<F,T1,T2>' being compiled 1> with 1> [ 1> F=boost::mpl::protect<boost::mpl::aux::iter_fold_if_pred<boost::mpl::protect<boost::detail::variant::find_fallback_type_pred>,boost::mpl::l_iter<boost::mpl::l_end>>>, 1> T1=boost::mpl::int_<1>, 1> T2=boost::mpl::l_iter<boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/aux_/preprocessed/plain/iter_fold_if_impl.hpp(62) : see reference to class template instantiation 'boost::mpl::apply2<F,T1,T2>' being compiled 1> with 1> [ 1> F=boost::mpl::protect<boost::mpl::aux::iter_fold_if_pred<boost::mpl::protect<boost::detail::variant::find_fallback_type_pred>,boost::mpl::l_iter<boost::mpl::l_end>>>, 1> T1=boost::mpl::int_<1>, 1> T2=boost::mpl::l_iter<boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/aux_/preprocessed/plain/iter_fold_if_impl.hpp(102) : see reference to class template instantiation 'boost::mpl::aux::iter_fold_if_forward_step<Iterator,State,ForwardOp,Predicate>' being compiled 1> with 1> [ 1> Iterator=boost::mpl::l_iter<boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>>, 1> State=boost::mpl::int_<1>, 1> ForwardOp=boost::mpl::protect<boost::mpl::next<boost::mpl::na>>, 1> Predicate=boost::mpl::protect<boost::mpl::aux::iter_fold_if_pred<boost::mpl::protect<boost::detail::variant::find_fallback_type_pred>,boost::mpl::l_iter<boost::mpl::l_end>>> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/iter_fold_if.hpp(94) : see reference to class template instantiation 'boost::mpl::aux::iter_fold_if_impl<Iterator,State,ForwardOp,ForwardPredicate,BackwardOp,BackwardPredicate>' being compiled 1> with 1> [ 1> Iterator=boost::mpl::l_iter<boost::mpl::l_item<boost::mpl::long_<3>,behavior_collection::null_behavior,boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>>>, 1> State=boost::mpl::int_<0>, 1> ForwardOp=boost::mpl::protect<boost::mpl::next<boost::mpl::na>>, 1> ForwardPredicate=boost::mpl::protect<boost::mpl::aux::iter_fold_if_pred<boost::mpl::protect<boost::detail::variant::find_fallback_type_pred>,boost::mpl::l_iter<boost::mpl::l_end>>>, 1> BackwardOp=boost::mpl::na, 1> BackwardPredicate=boost::mpl::always<boost::mpl::false_> 1> ] 1> C:\dev\boost\1.42.0\boost/mpl/iter_fold_if.hpp(102) : see reference to class template instantiation 'boost::mpl::iter_fold_if<Sequence,State,ForwardOp,ForwardPredicate>::result_' being compiled 1> with 1> [ 1> Sequence=boost::mpl::l_item<boost::mpl::long_<3>,behavior_collection::null_behavior,boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>>, 1> State=boost::mpl::int_<0>, 1> ForwardOp=boost::mpl::protect<boost::mpl::next<boost::mpl::na>>, 1> ForwardPredicate=boost::mpl::protect<boost::detail::variant::find_fallback_type_pred> 1> ] 1> C:\dev\boost\1.42.0\boost/variant/variant.hpp(170) : see reference to class template instantiation 'boost::mpl::iter_fold_if<Sequence,State,ForwardOp,ForwardPredicate>' being compiled 1> with 1> [ 1> Sequence=boost::mpl::l_item<boost::mpl::long_<3>,behavior_collection::null_behavior,boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>>, 1> State=boost::mpl::int_<0>, 1> ForwardOp=boost::mpl::protect<boost::mpl::next<boost::mpl::na>>, 1> ForwardPredicate=boost::mpl::protect<boost::detail::variant::find_fallback_type_pred> 1> ] 1> C:\dev\boost\1.42.0\boost/variant/variant.hpp(1079) : see reference to class template instantiation 'boost::detail::variant::find_fallback_type<Types>' being compiled 1> with 1> [ 1> Types=boost::mpl::l_item<boost::mpl::long_<3>,behavior_collection::null_behavior,boost::mpl::l_item<boost::mpl::long_<2>,std::vector<behavior_collection::behavior_impl<kinematic_output>>,boost::mpl::l_item<boost::mpl::long_<1>,std::vector<behavior_collection::behavior_impl<dynamic_output>>,boost::mpl::l_end>>> 1> ] 1> c:\users\zach\documents\visual studio 2010\projects\dxdemo\dxdemo\behavior_collection.h(39) : see reference to class template instantiation 'boost::variant<T0_,T1,T2>' being compiled 1> with 1> [ 1> T0_=behavior_collection::null_behavior, 1> T1=behavior_collection::kinematic_behaviors, 1> T2=behavior_collection::dynamic_behaviors 1> ]

Also, for the record, i realize the problem is probably related to variant requiring its bounded types to support the CopyConstructible concept, but my question is more along the lines of whether this requirement can be eliminated or relaxed in the presence of r-value refernces. I.e. Something along the lines of requiring one or more of CopyConstructible, MoveConstructible. Zach

On 02/23/10 00:04, Zachary Turner wrote:
Also, for the record, i realize the problem is probably related to variant requiring its bounded types to support the CopyConstructible concept, but my question is more along the lines of whether this requirement can be eliminated or relaxed in the presence of r-value refernces. I.e. Something along the lines of requiring one or more of CopyConstructible, MoveConstructible.
I don't know about r-value references as a solution; however, would one possible workaround be to derive from unique_ptr and then in the derived unique_ptr provide a copy CTOR? Although not for boost::variant, something like that was done in composite_tagged_seq.recur.test.cpp in composite_tagged_seq.zip in http://www.boostpro.com/vault/index.php?&directory=Data%20Structures. The derived unique_ptr was: boost::composite_tagged_recur::unique_ptr HTH. -regards, Larry

On 02/22/10 23:06, Zachary Turner wrote:
I have the following rough sequence of typedefs:
struct empty {}; typedef std::unique_ptr<foo> foo_ptr; typedef std::unique_ptr<bar> bar_ptr;
typedef std::vector<foo_ptr> foo_ptr_vec; typedef std::vector<bar_ptr> bar_ptr_vec;
typedef std::variant<empty, foo_ptr_vec, bar_ptr_vec> my_variant;
I then declare an instance of my_variant in a class, and make the class moveable and noncopyable.
class my_class { my_class(const my_class&); my_class& my_class(const my_class&);
my_variant v_;
public: my_class(my_class&& other) : v_(std::move(other.v_)) { } };
I cannot get this to compile under MSVC 10 and boost 1.42. In theory I don't see why this shouldn't be ok. Even though the objects are not copy-constructible due to unique_ptr, they are move constructible. The errors are quite long, but you can see it's trying to invoke vector::operator= from within the variant code.
Is this just a technical limitation of variant, or a bug?
The attached code produces output: ***after my_class default::CTOR: which=0 ***after foo_ptr::CTOR: fp.get=0x606010 ***after push: fp.get=0 fpv1.at(0).get()=0x606010 ***after move: fpv1.size()=0 fpv2.at(0).get()=0x606010 ***after inject: foo_ptr_vec which=1 fpv2.size()=0 x.project<1>()->at(0).get()=0x606010 Compilation finished at Fri Mar 26 17:25:54 If you're interested, I'll upload to the vault the latest version of composite_tagged_seq.hpp that was used to produce this. -regards, Larry
participants (2)
-
Larry Evans
-
Zachary Turner