Perfect forwarding type II
オレツエーtype II
前スレ: Perfect forwarding!! - にゃははー
こっちの方がSFINAEの度合い的に問題なさそう・・・
ってかforwardの定義がすごい簡略化できた。
Index: boost/move/move.hpp =================================================================== --- boost/move/move.hpp (revision 67436) +++ boost/move/move.hpp (working copy) @@ -27,9 +27,13 @@ #include <memory> //uninitialized_copy #include <iterator> //std::iterator #include <boost/mpl/if.hpp> +#include <boost/mpl/and.hpp> #include <boost/utility/enable_if.hpp> #include <boost/mpl/bool.hpp> #include <boost/type_traits/has_trivial_destructor.hpp> +#include <boost/type_traits/remove_cv.hpp> +#include <boost/type_traits/remove_reference.hpp> +#include <boost/type_traits/is_lvalue_reference.hpp> #include <boost/utility/addressof.hpp> //! Defining or undefining this macro will change Boost.Move behaviour @@ -91,6 +95,16 @@ enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) }; }; +template < typename T > +struct Move_ref_forwarding_ +{ + T * const ptr; + + explicit + Move_ref_forwarding_( T * const orig ) + : ptr( orig ) {} +}; + } //namespace move_detail { INTERPROCESS_NAMESPACE_END } //namespace boost { @@ -130,20 +144,113 @@ template <class T> struct is_rv -{ - static const bool value = false; -}; + : public ::boost::mpl::bool_< false > {}; template <class T> struct is_rv< rv<T> > + : public ::boost::mpl::bool_< true > {}; + +} //namespace move_detail { + +////////////////////////////////////////////////////////////////////////////// +// +// move_detail::is_rv_ref +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail { - static const bool value = true; + +template < typename T > +struct is_rv_ref + : public mpl::and_< + is_rv< typename remove_cv< + typename remove_reference< T >::type >::type >, + is_lvalue_reference< T > >::type {}; + +} // namespace move_detail + +////////////////////////////////////////////////////////////////////////////// +// +// move_detail::add_rv_ref +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail +{ + +template < typename T, bool = is_lvalue_reference< T >::value > +struct add_rv_ref; + +template < typename T > +struct add_rv_ref< T, false > +{ + typedef ::BOOST_MOVE_NAMESPACE::rv< T > & type; }; -} //namespace move_detail { +template < typename T > +struct add_rv_ref< const T, false > +{ + typedef const ::BOOST_MOVE_NAMESPACE::rv< T > & type; +}; +template < typename T > +struct add_rv_ref< volatile T, false > +{ + typedef volatile ::BOOST_MOVE_NAMESPACE::rv< T > & type; +}; + +template < typename T > +struct add_rv_ref< const volatile T, false > +{ + typedef const volatile ::BOOST_MOVE_NAMESPACE::rv< T > & type; +}; + +} // namespace move_detail + ////////////////////////////////////////////////////////////////////////////// // +// move_detail::remove_rv_ref +// +////////////////////////////////////////////////////////////////////////////// + +namespace move_detail +{ + +template < typename T > +struct remove_rv_ref +{ + typedef T type; +}; + +template < typename T > +struct remove_rv_ref< rv< T > & > +{ + typedef T type; +}; + +template < typename T > +struct remove_rv_ref< const rv< T > & > +{ + typedef const T type; +}; + +template < typename T > +struct remove_rv_ref< volatile rv< T > & > +{ + typedef volatile T type; +}; + +template < typename T > +struct remove_rv_ref< const volatile rv< T > & > +{ + typedef const volatile T type; +}; + +} // namespace move_detail + +////////////////////////////////////////////////////////////////////////////// +// // is_movable // ////////////////////////////////////////////////////////////////////////////// @@ -230,6 +337,7 @@ // ////////////////////////////////////////////////////////////////////////////// +/* originals template <class T> typename enable_if< ::BOOST_MOVE_NAMESPACE::move_detail::is_rv<T>, T &>::type forward(const typename move_detail::identity<T>::type &x) @@ -243,7 +351,26 @@ { return x; } +*/ +template < typename T > +typename lazy_disable_if< + ::BOOST_MOVE_NAMESPACE::move_detail::is_rv_ref< T >, + ::BOOST_MOVE_NAMESPACE::move_detail::add_rv_ref< T > >::type +forward( + ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< + typename ::BOOST_MOVE_NAMESPACE::move_detail::identity< T >::type > ref ) +{ return *ref.ptr; } + +template < typename T > +typename enable_if< + ::BOOST_MOVE_NAMESPACE::move_detail::is_rv_ref< T >, + T >::type +forward( + ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< + typename ::BOOST_MOVE_NAMESPACE::move_detail::remove_rv_ref< T >::type > ref ) +{ return *ref.ptr; } + #else //BOOST_MOVE_OPTIMIZED_EMULATION #define BOOST_COPY_ASSIGN_REF(TYPE)\ @@ -348,6 +475,10 @@ { return *reinterpret_cast< ::BOOST_MOVE_NAMESPACE::rv<TYPE>* >(this); }\ operator const ::BOOST_MOVE_NAMESPACE::rv<TYPE>&() const \ { return *reinterpret_cast<const ::BOOST_MOVE_NAMESPACE::rv<TYPE>* >(this); }\ + operator ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< S >( void ) \ + { return ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< S >( this ); } \ + operator const ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< const S >( void ) const \ + { return ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< const S >( this ); } \ private:\ // @@ -368,6 +499,10 @@ { return *reinterpret_cast< ::BOOST_MOVE_NAMESPACE::rv<TYPE>* >(this); }\ operator const ::BOOST_MOVE_NAMESPACE::rv<TYPE>&() const \ { return *reinterpret_cast<const ::BOOST_MOVE_NAMESPACE::rv<TYPE>* >(this); }\ + operator ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< S >( void ) \ + { return ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< S >( this ); } \ + operator const ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< const S >( void ) const \ + { return ::BOOST_MOVE_NAMESPACE::move_detail::Move_ref_forwarding_< const S >( this ); } \ private:\ //
アイディアのベースはstd::auto_ptrになってて、std::auto_ptrと違ってこっちは元クラスが正しくcopy/move-ctor/assignを定義/削除してるはずなので問題ないはず・・・
しかも変なSFINAEを使ってないからstd::auto_ptrの挙動を満たすコンパイラであれば基本的に動くはず。
例によってborlandとかmsvcとかのレビューくだしあ。
テストコードは前スレの奴がそのまま使えます。ってかC++0xで書いたコードが基本的にそのまま動く+正しくエラーを出すようになっていればおkです。
この流れならmove()も楽に作れそうだ・・・