TR1のrefを実装した。実装上の特徴、読みやすいコードを心がける。unary_functionとbinary_functionの両方を継承していても使える。多重継承を極力避ける。
実装方法は二転三転した。最終的にこのような実装になり、だいぶ満足している。Dinkumwareの実装よりは読みやすいだろう。
#ifndef HITO_REF #define HITO_REF #include <boost/type_traits/is_base_of.hpp> #include <boost/type_traits/integral_constant.hpp> #include <boost/mpl/has_xxx.hpp> namespace hito { namespace detail { // this macro generates a metafunction has_result_type<T>. // it returns true if T has nested type name T::result_type. // otherwise, it returns false. BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type) typedef char yes_type ; struct no_type { char padding[8] ; } ; template < typename T > struct is_base_of_unary_function_impl { template < typename R, typename T1 > static yes_type check( const volatile std::unary_function<T1, R> * ) ; static no_type check( const volatile void * ) ; static const bool value = sizeof( check( static_cast< T * >(NULL) ) ) == sizeof( yes_type ) ; } ; template < typename T > struct is_base_of_binary_function_impl { template < typename R, typename T1, typename T2 > static yes_type check( const volatile std::binary_function<T1, T2, R> * ) ; static no_type check( const volatile void * ) ; static const bool value = sizeof( check( static_cast< T * >(NULL) ) ) == sizeof( yes_type ) ; } ; // this metafunction returns true if T is derived from std::unary_function // otherwise, it returns false. template < typename T > struct is_base_of_unary_function : boost::integral_constant< bool, is_base_of_unary_function_impl<T>::value > { } ; // this metafunction returns true if T is derived from std::binary_function // otherwise, it returns false. template < typename T > struct is_base_of_binary_function : boost::integral_constant< bool, is_base_of_binary_function_impl<T>::value > { } ; // if T has nested type name result_type. // because TR1 only mentions about result_type, // we couldn't use argument_types, and couldn't know if it is a unary function or binary function or both. template < typename Derived, typename T > struct generic_invocation { typedef typename T::result_type result_type ; template < typename T1 > result_type operator () ( T1 const & arg1 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1 ) ; } template < typename T1, typename T2 > result_type operator () ( T1 const & arg1, T2 const & arg2 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1, arg2 ) ; } } ; // make base class. avoid multiple inheritance if possible. template < typename Derived, typename T, bool is_unary, bool is_binary, bool has_result > struct make_invocation_base { } ; // if T is derived from unary_function. template < typename Derived, typename T, bool val > struct make_invocation_base< Derived, T, true, false, val > : std::unary_function< typename T::argument_type, typename T::result_type > { result_type operator () ( argument_type const & arg1 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1 ) ; } } ; // if T is derived from binary_fucntion template < typename Derived, typename T, bool val > struct make_invocation_base< Derived, T, false, true, val > : std::binary_function< typename T::first_argument_type, typename T::second_argument_type, typename T::result_type > { result_type operator () ( first_argument_type const & arg1, second_argument_type const & arg2 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1, arg2 ) ; } } ; // if T is derived from both unary_function and binary_function. template < typename Derived, typename T, bool val > struct make_invocation_base< Derived, T, true, true, val > : std::unary_function< typename T::argument_type, typename T::result_type > , std::binary_function< typename T::first_argument_type, typename T::second_argument_type, typename T::result_type > { typedef typename T::result_type result_type ; result_type operator () ( argument_type const & arg1 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1 ) ; } result_type operator () ( first_argument_type const & arg1, second_argument_type const & arg2 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1, arg2 ) ; } } ; // else if it has nested type name result_type template < typename Derived, typename T > struct make_invocation_base< Derived, T, false, false, true > : generic_invocation< Derived, T > { } ; // Primary Template for reference_wrapper_invocation. // this class defines function call operator and inherites unary_function/binary_function or both. template < typename Derived, typename T > struct reference_wrapper_invocation : make_invocation_base< Derived, T , is_base_of_unary_function< T >::value , is_base_of_binary_function< T >::value , has_result_type< T >::value > { } ; // unary function type template < typename Derived, typename R, typename T1 > struct reference_wrapper_invocation< Derived, R(T1) > : std::unary_function< T1, R > { result_type operator() ( argument_type const & arg1 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1 ) ; } } ; // pointer to unary function type template < typename Derived, typename R, typename T1 > struct reference_wrapper_invocation< Derived, R(*)(T1) > : std::unary_function< T1, R > { result_type operator() ( argument_type const & arg1 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1 ) ; } } ; // pointer to nullary member function type template < typename Derived, typename R, typename T1 > struct reference_wrapper_invocation< Derived, R (T1::*)() > : std::unary_function< T1, R > { result_type operator() ( argument_type & arg1 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; // call T1's member function by a pointer. return (arg1.*self.get())( ) ; } } ; // pointer to nullary member function type with const qualifier template < typename Derived, typename R, typename T1 > struct reference_wrapper_invocation< Derived, R (T1::*)() const > : std::unary_function< T1, R > { result_type operator() ( argument_type & arg1 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; // call T1's member function by a pointer. return (arg1.*self.get())( ) ; } } ; // binary function type template < typename Derived, typename R, typename T1, typename T2 > struct reference_wrapper_invocation< Derived, R(T1, T2) > : std::binary_function< T1, T2, R > { result_type operator() ( first_argument_type const & arg1, second_argument_type const & arg2 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1, arg2 ) ; } } ; // pointer to binary function type template < typename Derived, typename R, typename T1, typename T2 > struct reference_wrapper_invocation< Derived, R(*)(T1, T2) > : std::binary_function< T1, T2, R > { result_type operator() ( first_argument_type const & arg1, second_argument_type const & arg2 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; return self.get()( arg1, arg2 ) ; } } ; // pointer to urnary member function type template < typename Derived, typename R, typename T1, typename T2 > struct reference_wrapper_invocation< Derived, R (T1::*)( T2 ) > : std::binary_function< T1, T2, R > { result_type operator() ( first_argument_type const & arg1, second_argument_type const & arg2 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; // call T1's member function by a pointer. return (arg1.*self.get())( arg2 ) ; } } ; // pointer to urnary member function type with const qualifier template < typename Derived, typename R, typename T1, typename T2 > struct reference_wrapper_invocation< Derived, R (T1::*)( T2 ) const > : std::binary_function< T1, T2, R > { result_type operator() ( first_argument_type const & arg1, second_argument_type const & arg2 ) const { Derived const & self = static_cast< Derived const & >( *this ) ; // call T1's member function by a pointer. return (arg1.*self.get())( arg2 ) ; } } ; } // namespace detail template < typename T > class reference_wrapper : public detail::reference_wrapper_invocation< reference_wrapper< T >, T > { public : typedef T type ; reference_wrapper( T & x ) : object( &x ) { } reference_wrapper( const reference_wrapper< T > & x ) : object( &x.get() ) { } reference_wrapper & operator = ( const reference_wrapper< T > & x ) { if ( this != &x ) { object = &x.get() ; } return *this ; } operator T & () const { return get() ; } T & get() const { return *object ; } private : T * object ; } ; // reference_wrapper helper functions template < typename T > reference_wrapper< T > ref( T & t ) { return reference_wrapper< T >( t ) ; } template < typename T > reference_wrapper< T > ref( reference_wrapper< T > t ) { return ref( t.get() ) ; } template < typename T > reference_wrapper< T const > cref( T const & t ) { return reference_wrapper< T const >( t ) ; } template < typename T > reference_wrapper< T const > cref( reference_wrapper< T > t ) { return cref( t.get() ) ; } } // namespace hito #endif // #ifndef HITO_REF
追記:
やはりどうも、メンバを参照で持つのは無理みたいだ。ポインタに直した。
No comments:
Post a Comment
You can use some HTML elements, such as <b>, <i>, <a>, also, some characters need to be entity referenced such as <, > and & Your comment may need to be confirmed by blog author. Your comment will be published under GFDL 1.3 or later license with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.