誰かが、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