誰かが、Boost::functionを読めばレベルが3ぐらい上がるとつぶやいていた。読もうとしたが、五分で諦めた。プリプロセッサを使いすぎなのだ。だいたい、std::functionぐらいなら、自分で実装した方が、レベルが上がるのではないかと思う。というわけで、4時間ぐらいかけて、書いてみた。
アロケーターも、似たようなType Erasureのテクニックを使って実装すればいい。
ところで、target_type()の文面がよく分からない。Tとあるが、target_type()はテンプレートではないし、Tが定義されていないのではないか。
追記、target_type()を理解したが、実装方法が面倒だ。さて、どうするか。
追記、target_type()/target()を実装した。さらに、perfect forwardingになった。
namespace hito {
class bad_function_call : public std::exception
{
public:
bad_function_call() {}
virtual char const * what() const throw()
{
return "bad function call exception" ;
}
} ;
template < typename > class function ;// primary template.
template < typename R, typename ... ArgTypes >
class function< R ( ArgTypes... ) >
{
public :
typedef R result_type ;
private :
struct holder_base
{
virtual ~holder_base() {}
virtual holder_base * clone() const = 0 ;
virtual std::type_info const & target_type() const = 0 ;
virtual void * target() = 0 ;
virtual result_type invoke( ArgTypes... ) = 0 ;
} ;
template < typename F >
struct holder : public holder_base
{
public :
holder(F f) : f( f )
{ }
virtual ~holder() { }
virtual holder_base * clone() const
{
return allocate_holder( f ) ;
}
virtual std::type_info const & target_type() const
{
return typeid( F ) ;
}
virtual void * target()
{
return &f ;
}
virtual result_type invoke( ArgTypes... args )
{
return f( std::forward<ArgTypes>(args)... ) ;
}
private :
F f ;
} ;
template < typename holder_R, typename T, typename ... Types >
struct member_holder : public holder_base
{
public :
member_holder( holder_R (T::* const f)( Types... ) )
: f(f)
{ }
virtual ~member_holder() {}
virtual holder_base * clone() const
{
return allocate_holder( f ) ;
}
virtual std::type_info const & target_type() const
{
return typeid( f ) ;
}
virtual void * target()
{
return &f ;
}
result_type invoke_impl( T t1, Types... args )
{
return (t1.*f)( std::forward<Types>(args)... ) ;
}
result_type invoke_impl( T * t1, Types... args )
{
return ((*t1).*f)( std::forward<Types>(args)... ) ;
}
virtual result_type invoke( ArgTypes ... args )
{
return invoke_impl( std::forward<ArgTypes>(args)... ) ;
}
private :
holder_R (T::* f)( Types...) ;
} ;
template < typename T, typename DATA >
struct data_member_holder : holder_base
{
public :
data_member_holder( DATA T::* const f )
: f( f )
{ }
virtual ~data_member_holder() { }
virtual holder_base * clone() const
{
return allocate_holder( f ) ;
}
virtual std::type_info const & target_type() const
{
return typeid( f ) ;
}
virtual void * target()
{
return &f ;
}
result_type invoke_impl( T & t1 )
{
return t1.*f ;
}
result_type invoke_impl( T * const t1 )
{
return (*t1).*f ;
}
virtual result_type invoke( ArgTypes ... args )
{
return invoke_impl( args... ) ;
}
private :
DATA T::* f ;
} ;
holder_base * ptr ;
private :
template < typename F >
static holder_base * allocate_holder(F f)
{
return new holder< F >( f ) ;
}
template < typename holder_R, typename T, typename ... Types >
static holder_base * allocate_holder( holder_R (T::* f)( Types... ) )
{
return new member_holder<holder_R, T, Types...>( f ) ;
}
template < typename T, typename DATA >
static holder_base * allocate_holder( DATA T::* f )
{
return new data_member_holder<T, DATA>( f ) ;
}
void deallocate_holder()
{
delete ptr ;
ptr = nullptr ;
}
holder_base * clone() const
{
if ( ptr != nullptr )
return ptr->clone() ;
else
return nullptr ;
}
public :
explicit function() : ptr( nullptr ) { }
function( std::nullptr_t ) : ptr( nullptr ) { }
function( function const & init_expr )
: ptr( init_expr.clone() )
{ }
function( function && init_expr )
: ptr( init_expr.ptr )
{
init_expr.ptr = nullptr ;
}
template < typename F >
function( F f )
: ptr( allocate_holder( f ) )
{ }
function & operator = ( function const & assign_expr )
{
if ( this == &assign_expr )
return *this ;
deallocate_holder() ;
this->ptr = assign_expr.clone() ;
return *this ;
}
function & operator = ( function && assign_expr )
{
if ( this == &assign_expr )
return *this ;
deallocate_holder() ;
this->ptr = assign_expr.ptr ;
assign_expr.ptr = nullptr ;
return *this ;
}
function & operator = ( std::nullptr_t )
{
deallocate_holder() ;
return *this ;
}
template < typename F >
function & operator = ( F f )
{
delete ptr ;
ptr = allocate_holder( f ) ;
}
~function()
{
deallocate_holder() ;
}
void swap( function & arg )
{
std::swap( this->ptr, arg.ptr ) ;
}
explicit operator bool() const
{
return bool( ptr != nullptr ) ;
}
result_type operator () ( ArgTypes... args ) const
{
if ( ptr != nullptr)
return ptr->invoke( std::forward<ArgTypes>(args)... ) ;
else
throw bad_function_call() ;
}
std::type_info const & target_type() const
{
if ( ptr != nullptr )
return ptr->target_type() ;
else
return typeid( void ) ;
}
template < typename T >
T * target()
{
if ( target_type() == typeid(T) )
return static_cast<T *>( ptr->target() ) ;
else
return nullptr ;
}
template < typename T >
T const * target() const
{
if ( target_type() == typeid(T) )
return static_cast<T const *>( ptr->target() ) ;
else
return nullptr ;
}
} ;
}
No comments:
Post a Comment