Created
December 15, 2013 21:04
-
-
Save athanase/7978090 to your computer and use it in GitHub Desktop.
Functor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <tuple> | |
template <typename... Args> | |
struct variadic_typedef | |
{ | |
// this single type represents a collection of types, | |
// as the template arguments it took to define it | |
}; | |
template <typename... Args> | |
struct convert_in_tuple | |
{ | |
// base case, nothing special, | |
// just use the arguments directly | |
// however they need to be used | |
typedef std::tuple<Args...> type; | |
}; | |
template <typename... Args> | |
struct convert_in_tuple<variadic_typedef<Args...>> | |
{ | |
// expand the variadic_typedef back into | |
// its arguments, via specialization | |
// (doesn't rely on functionality to be provided | |
// by the variadic_typedef struct itself, generic) | |
typedef typename convert_in_tuple<Args...>::type type; | |
}; | |
///------------------------------------------------------------------------ | |
/// | |
/// class template FunctorImpl (internal) | |
/// | |
namespace Private | |
{ | |
template | |
< | |
typename R | |
> | |
struct FunctorImplBase | |
{ | |
typedef R ResultType; | |
typedef FunctorImplBase<R> FunctorImplBaseType; | |
virtual ~FunctorImplBase() | |
{} | |
virtual FunctorImplBase* DoClone() const = 0; | |
template <class U> | |
static U* Clone(U* pObj) | |
{ | |
if( not pObj ) return 0; | |
U* pClone = static_cast<U*>( pObj->DoClone() ); | |
assert( typeid(*pClone) == typeid(*pObj) ); | |
return pClone; | |
} | |
}; | |
} | |
/// macro LOKI_DEFINE_CLONE_FUNCTORIMPL | |
/// Implements the DoClone function for a functor implementation | |
#define LOKI_DEFINE_CLONE_FUNCTORIMPL(Cls) \ | |
virtual Cls* DoClone() const { return new Cls(*this); } | |
///---------------------------------------------------------------------------- | |
/// | |
/// class template FunctorImpl | |
/// Specialization for 1 parameter | |
/// | |
template | |
< | |
typename R, | |
typename ...TList | |
> | |
class FunctorImpl | |
: public Private::FunctorImplBase<R> | |
{ | |
public: | |
typedef R ResultType; | |
typedef variadic_typedef<TList...> ParmList; | |
typedef variadic_typedef<TList...> MyList; | |
typedef convert_in_tuple<MyList> MyVarList; | |
virtual R operator()( MyList&& parms ) = 0; | |
}; | |
///------------------------------------------------------------------------ | |
/// | |
/// class template FunctorHandler | |
/// Wraps functors and pointers to functions | |
/// | |
template <class ParentFunctor, typename Fun> | |
class FunctorHandler | |
: public ParentFunctor::Impl | |
{ | |
typedef typename ParentFunctor::Impl Base; | |
public: | |
typedef typename Base::ResultType ResultType; | |
typedef typename Base::MyList MyList; | |
typedef typename Base::MyVarList MyVarList; | |
FunctorHandler( const Fun& fun ) : f_(fun) {} | |
LOKI_DEFINE_CLONE_FUNCTORIMPL(FunctorHandler) | |
// operator() implementations | |
ResultType operator()( MyList&& parms ) | |
{ return f_( std::forward<MyVarList>(parms) ); } | |
private: | |
Fun f_; | |
}; | |
///------------------------------------------------------------------------ | |
/// | |
/// class template FunctorHandler | |
/// Wraps pointers to member functions | |
/// | |
template <class ParentFunctor, typename PointerToObj, | |
typename PointerToMemFn> | |
class MemFunHandler : public ParentFunctor::Impl | |
{ | |
typedef typename ParentFunctor::Impl Base; | |
public: | |
typedef typename Base::ResultType ResultType; | |
typedef typename Base::MyList MyList; | |
typedef typename Base::MyVarList MyVarList; | |
MemFunHandler( const PointerToObj& pObj, PointerToMemFn pMemFn ) | |
: pObj_( pObj ) | |
, pMemFn_( pMemFn ) | |
{} | |
LOKI_DEFINE_CLONE_FUNCTORIMPL(MemFunHandler) | |
ResultType operator()( MyList&& parms ) | |
{ return ((*pObj_).*pMemFn_)( std::forward<MyVarList>(parms) ); } | |
private: | |
PointerToObj pObj_; | |
PointerToMemFn pMemFn_; | |
}; | |
///------------------------------------------------------------------------ | |
/// | |
/// TR1 exception | |
/// | |
#ifdef LOKI_ENABLE_FUNCTION | |
class bad_function_call : public std::runtime_error | |
{ | |
public: | |
bad_function_call() : std::runtime_error("bad_function_call in Loki::Functor") | |
{} | |
}; | |
#define LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL if(empty()) throw bad_function_call(); | |
#else | |
#define LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL | |
#endif | |
template | |
< | |
typename R = void, | |
class ...TList | |
> | |
class Functor | |
{ | |
public: | |
// Handy type definitions for the body type | |
typedef FunctorImpl<R, TList...> Impl; | |
typedef R ResultType; | |
typedef typename Impl::MyList MyList; | |
typedef typename Impl::MyVarList MyVarList; | |
// Member functions | |
Functor() : spImpl_(0) | |
{} | |
Functor( const Functor& rhs ) : spImpl_( Impl::Clone(rhs.spImpl_.get()) ) | |
{} | |
Functor( std::auto_ptr<Impl> spImpl ) : spImpl_( spImpl ) | |
{} | |
template <typename Fun> | |
Functor(Fun fun) | |
: spImpl_( new FunctorHandler<Functor, Fun>(fun) ) | |
{} | |
template <class PtrObj, typename MemFn> | |
Functor( const PtrObj& p, MemFn memFn ) | |
: spImpl_( new MemFunHandler<Functor, PtrObj, MemFn>(p, memFn) ) | |
{} | |
typedef Impl * (std::auto_ptr<Impl>::*unspecified_bool_type)() const; | |
operator unspecified_bool_type() const | |
{ | |
return spImpl_.get() ? &std::auto_ptr<Impl>::get : 0; | |
} | |
Functor& operator=(const Functor& rhs) | |
{ | |
Functor copy(rhs); | |
// swap auto_ptrs by hand | |
Impl* p = spImpl_.release(); | |
spImpl_.reset(copy.spImpl_.release()); | |
copy.spImpl_.reset(p); | |
return *this; | |
} | |
#ifdef LOKI_ENABLE_FUNCTION | |
bool empty() const | |
{ | |
return spImpl_.get() == 0; | |
} | |
void clear() | |
{ | |
spImpl_.reset(0); | |
} | |
#endif | |
bool operator==(const Functor& rhs) const | |
{ | |
if( spImpl_.get() == 0 and rhs.spImpl_.get() == 0 ) | |
return true; | |
if( spImpl_.get() != 0 && rhs.spImpl_.get() !=0 ) | |
return *spImpl_.get() == *rhs.spImpl_.get(); | |
else | |
return false; | |
} | |
bool operator!=(const Functor& rhs) const | |
{ | |
return !(*this==rhs); | |
} | |
// operator() implementations | |
ResultType operator()( MyList&& parms ) const | |
{ | |
LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL | |
return (*spImpl_)( std::forward<MyVarList>(parms) ); | |
} | |
private: | |
std::auto_ptr<Impl> spImpl_; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment