2008-09-20

やったー、std::tr1:refが実装できたよ

TR1のrefを実装した。実装上の特徴、読みやすいコードを心がける。unary_functionとbinary_functionの両方を継承していても使える。多重継承を極力避ける。

実装方法は二転三転した。最終的にこのような実装になり、だいぶ満足している。Dinkumwareの実装よりは読みやすいだろう。

pastbinに貼り付けたソースコード

#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.