//#include #include "move.hpp" #include #include #include #include #include #include enum ConstructionType { Default, Copied, Moved, Other }; class conversion_source { public: conversion_source(){} operator int() const { return 0; } }; class conversion_target { ConstructionType c_type_; public: conversion_target(conversion_source) { c_type_ = Other; } conversion_target() { c_type_ = Default; } conversion_target(const conversion_target &) { c_type_ = Copied; } ConstructionType construction_type() const { return c_type_; } }; class conversion_target_copymovable { ConstructionType c_type_; BOOST_COPYABLE_AND_MOVABLE(conversion_target_copymovable) public: conversion_target_copymovable() { c_type_ = Default; } conversion_target_copymovable(conversion_source) { c_type_ = Other; } conversion_target_copymovable(const conversion_target_copymovable &) { c_type_ = Copied; } conversion_target_copymovable(BOOST_RV_REF(conversion_target_copymovable) ) { c_type_ = Moved; } conversion_target_copymovable &operator=(BOOST_RV_REF(conversion_target_copymovable) ) { c_type_ = Moved; return *this; } conversion_target_copymovable &operator=(BOOST_COPY_ASSIGN_REF(conversion_target_copymovable) ) { c_type_ = Copied; return *this; } ConstructionType construction_type() const { return c_type_; } }; class conversion_target_movable { ConstructionType c_type_; BOOST_MOVABLE_BUT_NOT_COPYABLE(conversion_target_movable) public: conversion_target_movable() { c_type_ = Default; } conversion_target_movable(conversion_source) { c_type_ = Other; } conversion_target_movable(BOOST_RV_REF(conversion_target_movable) ) { c_type_ = Moved; } conversion_target_movable &operator=(BOOST_RV_REF(conversion_target_movable) ) { c_type_ = Moved; return *this; } ConstructionType construction_type() const { return c_type_; } }; struct not_a_type; #if defined(BOOST_NO_RVALUE_REFERENCES) #define BOOST_MOVE_CATCH_CONST(U) \ typename ::boost::mpl::if_< ::boost::is_class, BOOST_CATCH_CONST_RLVALUE(U), const U &>::type #define BOOST_MOVE_CATCH_RVALUE(U)\ typename ::boost::mpl::if_< ::boost::is_class, BOOST_RV_REF(T), not_a_type>::type #else #define BOOST_MOVE_CATCH_CONST(U) BOOST_CATCH_CONST_RLVALUE(U) #define BOOST_MOVE_CATCH_RVALUE(U) BOOST_RV_REF(U) #endif // BEGIN JLH additional definitions... template< class T > struct remove_const_remove_reference { typedef T type; }; template< class T > struct remove_const_remove_reference< const T > : remove_const_remove_reference { }; template< class T > struct remove_const_remove_reference< volatile T > : remove_const_remove_reference { }; template< class T > struct remove_const_remove_reference< const volatile T > : remove_const_remove_reference { }; template< class T > struct remove_const_remove_reference< T& > : remove_const_remove_reference { }; template< class T > struct remove_const_remove_reference< boost::rv > : remove_const_remove_reference { }; template< class T > struct add_reference_add_const { typedef T const & type; }; template< class T > struct add_reference_add_const< T& > { typedef T& type; }; template< class T, class U > struct is_same_sans_const_sans_reference : boost::is_same< typename remove_const_remove_reference::type, typename remove_const_remove_reference::type > { }; template< class T > struct add_lvalue_reference { typedef T& type; }; template<> struct add_lvalue_reference< void > { typedef void type; }; template<> struct add_lvalue_reference< const void > { typedef const void type; }; template<> struct add_lvalue_reference< volatile void > { typedef volatile void type; }; template<> struct add_lvalue_reference< const volatile void > { typedef const volatile void type; }; template< class T > struct add_lvalue_reference< T& > { typedef T& type; }; template< class T > struct add_lvalue_reference< boost::rv > { typedef T& type; }; template< class T > struct add_lvalue_reference< const boost::rv > { typedef const T& type; }; template< class T > struct add_lvalue_reference< volatile boost::rv > { typedef volatile T& type; }; template< class T > struct add_lvalue_reference< const volatile boost::rv > { typedef const volatile T& type; }; template< class T > struct add_lvalue_reference< boost::rv& > { typedef T& type; }; template< class T > struct add_lvalue_reference< const boost::rv& > { typedef const T& type; }; template< class T > struct add_lvalue_reference< volatile boost::rv& > { typedef volatile T& type; }; template< class T > struct add_lvalue_reference< const volatile boost::rv& > { typedef const volatile T& type; }; template< class T > struct remove_rvalue_reference { typedef T type; }; template< class T > struct remove_rvalue_reference< boost::rv > { typedef T type; }; template< class T > struct remove_rvalue_reference< const boost::rv > { typedef T type; }; template< class T > struct remove_rvalue_reference< volatile boost::rv > { typedef T type; }; template< class T > struct remove_rvalue_reference< const volatile boost::rv > { typedef T type; }; template< class T > struct remove_rvalue_reference< boost::rv& > { typedef T type; }; template< class T > struct remove_rvalue_reference< const boost::rv& > { typedef T type; }; template< class T > struct remove_rvalue_reference< volatile boost::rv& > { typedef T type; }; template< class T > struct remove_rvalue_reference< const volatile boost::rv& > { typedef T type; }; template< class T > struct add_rvalue_reference : boost::mpl::if_< boost::has_move_emulation_enabled, boost::rv&, T > { }; template< class T > struct remove_crv : remove_rvalue_reference { }; template< class T > struct remove_crv< const T > : remove_rvalue_reference { }; template< class T > inline typename add_lvalue_reference::type as_lvalue(T& x) { return x; } // END JLH additional definitions... template class container { typename ::boost::aligned_storage::value>::type storage_; public: ConstructionType construction_type() const { return construction_type_impl(typename ::boost::is_class::type()); } ConstructionType construction_type_impl(::boost::true_type) const { return reinterpret_cast(storage_).construction_type(); } ConstructionType construction_type_impl(::boost::false_type) const { return Copied; } #if 0 // Ion's original implementation void push_back(BOOST_MOVE_CATCH_CONST(T) x) { return priv_push_back(static_cast(x)); } void push_back(BOOST_MOVE_CATCH_RVALUE(T) x) { return priv_push_back(::boost::move(x)); } //Tricks for C++03 #if defined(BOOST_NO_RVALUE_REFERENCES) void push_back(T &x) { priv_push_back(const_cast(x)); } template typename ::boost::enable_if_c < ::boost::is_class::value && ::boost::is_same::value && !::boost::has_move_emulation_enabled::value >::type push_back(const U &u) { return priv_push_back(u); } template typename ::boost::enable_if_c < ::boost::is_class::value && !::boost::is_same::value && !::boost::move_detail::is_rv::value >::type push_back(const U &u) { T t(u); priv_push_back(::boost::move(t)); } #endif private: template void priv_push_back(BOOST_FWD_REF(U) x) { new (&storage_) T(::boost::forward(x)); } #else // #if 0|1 // JLH's current implementation (roughly; only showing C++03 here) template< class U > typename boost::disable_if< is_same_sans_const_sans_reference >::type push_back(const U& x) { priv_push_back(as_lvalue(x)); } template< class U > void push_back(U& x) { priv_push_back(x); } typedef typename add_reference_add_const< typename add_rvalue_reference::type >::type rv_param_type; void push_back(rv_param_type x) { priv_push_back(x); } private: template< class U > void priv_push_back(U& x) { new (&storage_) T(x); } #endif // #if 0|1 }; int main() { conversion_target_movable a; conversion_target_movable b(::boost::move(a)); { container c; { conversion_target x; c.push_back(x); assert(c.construction_type() == Copied); } { const conversion_target x; c.push_back(x); assert(c.construction_type() == Copied); } { c.push_back(conversion_target()); assert(c.construction_type() == Copied); } { conversion_source x; c.push_back(x); //assert(c.construction_type() == Copied); assert(c.construction_type() == Other); } { const conversion_source x; c.push_back(x); //assert(c.construction_type() == Copied); assert(c.construction_type() == Other); } { c.push_back(conversion_source()); //assert(c.construction_type() == Copied); assert(c.construction_type() == Other); } } { container c; { conversion_target_copymovable x; c.push_back(x); assert(c.construction_type() == Copied); } { const conversion_target_copymovable x; c.push_back(x); assert(c.construction_type() == Copied); } { c.push_back(conversion_target_copymovable()); assert(c.construction_type() == Moved); } { conversion_source x; c.push_back(x); //assert(c.construction_type() == Moved); assert(c.construction_type() == Other); } { const conversion_source x; c.push_back(x); //assert(c.construction_type() == Moved); assert(c.construction_type() == Other); } { c.push_back(conversion_source()); //assert(c.construction_type() == Moved); assert(c.construction_type() == Other); } } { container c; //This should not compile {/* conversion_target_movable x; c.push_back(x); assert(c.construction_type() == Copied); } { const conversion_target_movable x; c.push_back(x); assert(c.construction_type() == Copied); */} { c.push_back(conversion_target_movable()); assert(c.construction_type() == Moved); } { conversion_source x; c.push_back(x); //assert(c.construction_type() == Moved); assert(c.construction_type() == Other); } { const conversion_source x; c.push_back(x); //assert(c.construction_type() == Moved); assert(c.construction_type() == Other); } { c.push_back(conversion_source()); //assert(c.construction_type() == Moved); assert(c.construction_type() == Other); } } { container c; { int x; c.push_back(x); assert(c.construction_type() == Copied); } { const int x = 0; c.push_back(x); assert(c.construction_type() == Copied); } { c.push_back(int(0)); assert(c.construction_type() == Copied); } { conversion_source x; c.push_back(x); assert(c.construction_type() == Copied); } { const conversion_source x; c.push_back(x); assert(c.construction_type() == Copied); } { c.push_back(conversion_source()); assert(c.construction_type() == Copied); } } return 0; }