にゃははー

はへらー

Perfect forwarding!!

とりあえずオレツエー状態。

あとdiffはどっかに貼るべきだったかな・・・


で、
GCC4.4.4-14ubuntu5
GCC4.5.2
GCC4.6.0 20101223 (experimental)
Clang2.9(svn118883)
で確認。

多分BorlandとかmsvcだとSFINAEの挙動が若干変わって悲しいことになりそう。

Index: boost/move/move.hpp
===================================================================
--- boost/move/move.hpp (revision 67436)
+++ boost/move/move.hpp (working copy)
@@ -27,10 +27,19 @@
 #include <memory>    //uninitialized_copy
 #include <iterator>  //std::iterator
 #include <boost/mpl/if.hpp>
+#include <boost/mpl/not.hpp>
+#include <boost/mpl/or.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/type_traits/is_const.hpp>
+#include <boost/type_traits/is_volatile.hpp>
 #include <boost/utility/addressof.hpp>
+#include <boost/static_assert.hpp>
 
 //! Defining or undefining this macro will change Boost.Move behaviour 
 //! for copyable and movable classes when assigning from non-const rvalues:
@@ -130,20 +139,82 @@
 
 template <class T>
 struct is_rv
+  : public ::boost::mpl::bool_<false>
 {
-   static const bool value = false;
 };
 
 template <class T>
 struct is_rv< rv<T> >
+  : public ::boost::mpl::bool_<true>
 {
-   static const bool value = true;
 };
 
 }  //namespace move_detail {
 
 //////////////////////////////////////////////////////////////////////////////
 //
+//                            move_detail::is_rv_ref
+//
+//////////////////////////////////////////////////////////////////////////////
+
+namespace move_detail
+{
+
+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_const< T >::value,
+  bool = is_volatile< T >::value >
+struct add_rv_ref;
+
+template < typename T >
+struct add_rv_ref< T, false, false >
+{
+    typedef ::BOOST_MOVE_NAMESPACE::rv< T > & type;
+};
+
+template < typename T >
+struct add_rv_ref< T, false, true >
+{
+    typedef typename remove_cv< T >::type Ty_;
+    typedef volatile ::BOOST_MOVE_NAMESPACE::rv< Ty_ > & type;
+};
+
+template < typename T >
+struct add_rv_ref< T, true, false >
+{
+    typedef typename remove_cv< T >::type Ty_;
+    typedef const ::BOOST_MOVE_NAMESPACE::rv< Ty_ > & type;
+};
+
+template < typename T >
+struct add_rv_ref< T, true, true >
+{
+    typedef typename remove_cv< T >::type Ty_;
+    typedef const volatile ::BOOST_MOVE_NAMESPACE::rv< Ty_ > & type;
+};
+
+} // namespace move_detail
+
+//////////////////////////////////////////////////////////////////////////////
+//
 //                               is_movable
 //
 //////////////////////////////////////////////////////////////////////////////
@@ -230,6 +301,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 +315,86 @@
 {
    return x;
 }
+*/
 
+// explicitly lvalue reference
+template < typename T >
+typename enable_if<
+  typename mpl::and_<
+    typename mpl::not_< ::BOOST_MOVE_NAMESPACE::move_detail::is_rv_ref< T > >::type,
+    is_lvalue_reference< T > >::type,
+  const T & >::type
+forward( typename ::BOOST_MOVE_NAMESPACE::move_detail::identity< T >::type x )
+{
+    BOOST_STATIC_ASSERT( !is_lvalue_reference< T >::value );
+    return x;
+}
+
+// rvalue reference
+template < typename T >
+typename enable_if<
+  ::BOOST_MOVE_NAMESPACE::move_detail::is_rv< typename remove_reference< T >::type >,
+  typename remove_reference< T >::type & >::type
+forward( typename ::BOOST_MOVE_NAMESPACE::move_detail::identity< T >::type &x )
+{
+    return const_cast< T & >( x );
+}
+
+// lvalue reference
+template < typename T >
+typename disable_if<
+  typename mpl::or_<
+    ::BOOST_MOVE_NAMESPACE::move_detail::is_rv_ref< T >,
+    is_lvalue_reference< T > >::type,
+  const typename remove_reference< T >::type & >::type
+forward( typename ::BOOST_MOVE_NAMESPACE::move_detail::identity< T >::type &x )
+{
+    return x;
+}
+
+namespace move_detail
+{
+
+template < typename T, bool >
+struct forward_helper
+{
+    template < typename U >
+    forward_helper( U & );
+};
+
+template < typename T >
+struct forward_helper< T, false >
+{
+    forward_helper( const T &x )
+      : r( static_cast< const BOOST_RV_REF( T ) >( x ) ) {}
+
+    const BOOST_RV_REF( T ) r;
+};
+
+} // namespace move_detail
+
+// implicitly const Lv-ref reference
+template < typename T >
+typename disable_if<
+  typename mpl::or_<
+    ::BOOST_MOVE_NAMESPACE::move_detail::is_rv_ref< T >,
+    is_lvalue_reference< T > >::type,
+  const typename remove_reference< T >::type & >::type
+forward( ::BOOST_MOVE_NAMESPACE::move_detail::forward_helper< T, true > x );
+
+// reference to temporary obj
+template < typename T >
+typename lazy_disable_if<
+  typename mpl::or_<
+    ::BOOST_MOVE_NAMESPACE::move_detail::is_rv_ref< T >,
+    is_lvalue_reference< T > >::type,
+  ::BOOST_MOVE_NAMESPACE::move_detail::add_rv_ref< T > >::type
+forward( ::BOOST_MOVE_NAMESPACE::move_detail::forward_helper< T, false > x )
+{
+    using ::BOOST_MOVE_NAMESPACE::move_detail::add_rv_ref;
+    return const_cast< typename add_rv_ref< T >::type >( x.r );
+}
+
 #else //BOOST_MOVE_OPTIMIZED_EMULATION
 
 #define BOOST_COPY_ASSIGN_REF(TYPE)\

糞長いdiffですません...

とりあえずこれを適用すると、以下のコードが期待したとおりに動くはずです。

#include <boost/move/move.hpp>

struct S
{
    BOOST_COPYABLE_AND_MOVABLE( S )

public:
    S() {}
    S( BOOST_COPY_ASSIGN_REF( S ) ) {}
    S( BOOST_RV_REF( S ) ) {}

    void operator=( const BOOST_RV_REF( S ) ) {}

    void f( void ) const {}
};

int main( void )
{
    {
        S                 s  = boost::forward< BOOST_RV_REF( S ) >( S() );
        BOOST_RV_REF( S ) rs = boost::forward< BOOST_RV_REF( S ) >( s );
        rs.f();
    }

    {
        S       s   = boost::forward< S >( S() );
        const S &ls = boost::forward< S >( s );
        ls.f();
    }

    {
        const S s;
        const S &ls = boost::forward< const S >( s );
        ls.f();
    }

    {
        const S s;
        boost::forward< S >( s ).f(); // compile error
    }
}

最後のforwardは曖昧な関数呼出になってエラーになるはずです。できればstatic_assertとかにしたかったけど、まぁ及第点ぐらい?

msvcでの実験結果とかborlandでの結果とか送ってもらえたりしたら嬉しいです。手元でテストできないだろうから修正できるか分からないけど・・・