だいぶ前の記事では、target()の意味を勘違いしていた。void *へのキャストが出てくるので、おかしいと思ったのだ。しかし、std::functionのtargetって誰が使うんだ、これ。
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 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 result_type invoke( ArgTypes... args ) { return f( std::forward<ArgTypes>(args)... ) ; } 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 ) ; } 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)... ) ; } 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 ) ; } 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... ) ; } DATA T::* f ; } ; holder_base * ptr ; private : template < typename F > struct make_holder_type { typedef holder < F > type ; } ; template < typename holder_R, typename T, typename ... Types > struct make_holder_type< holder_R (T::*)( Types... ) > { typedef member_holder<holder_R, T, Types...> type ; } ; template < typename T, typename DATA > struct make_holder_type< DATA T::* > { typedef data_member_holder<T, DATA> type ; } ; template < typename F > static holder_base * allocate_holder(F f) { typedef typename make_holder_type<F>::type type ; return new type( 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 nullptr ; typedef typename make_holder_type<T>::type type ; auto actual_ptr = static_cast< type * >( ptr ) ; return &actual_ptr->f ; } template < typename T > T const * target() const { if ( target_type() != typeid(T) ) return nullptr ; typedef typename make_holder_type<T>::type type ; auto actual_ptr = static_cast< type * >( ptr ) ; return &actual_ptr->f ; } } ; }
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.