Skip to content

Instantly share code, notes, and snippets.

@athanase
Created December 15, 2013 21:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save athanase/7978090 to your computer and use it in GitHub Desktop.
Save athanase/7978090 to your computer and use it in GitHub Desktop.
Functor
#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