您的位置:首页 > 编程语言 > C语言/C++

comment:Yet Another Generalized Functors Implementation in C++

2010-12-16 11:29 489 查看
source : http://www.codeproject.com/KB/cpp/genfunctors.aspx

source code here:

http://www.google.cn/codesearch/p?hl=zh-CN#Sm49eXhuoDE/trunk/delta3d/inc/dtUtil/functor.h&q=struct%20FunImplBase&d=4

personal comment:

functor template class hold returnType , paramsListType, storedType param,

storedType could be initialized to store diff func pointer (nonconst/const /volotile func pointer or class member func pointer) when using diff functor consturct

cause we typedef diff pointer type as storedType within diff functor constructor

functor operator transmit the func call returnType and paramList to funcImp class's static member func of Call() ,

the funcImp is constructed and stored in Typeless.buffer[] which is encapsulated in storedType

like bridge pattern , using macro def of DoCall(params) to bridge multi overloaded functor::operator() to single vptr_->call_(*this, parms);

why we instantiate template class funcImpl or MemberFuncImpl which inherit from template class FunStorageImpl cause we want to initialize FunImplBase::VTable in an uniform way,

if not then assign FunImplBase::VTable will consume effort of instantiate instace of corresponding template FunStorageImpl

class diagram





code snippet

template <class R, class TList, unsigned int size=4*sizeof(void*)>

class functor

{

typedef R ReturnType;

typedef TList TypeListType;

typedef typename CallParams<TList>::ParamsListType ParamsListType;

//default constructor, destructor, assignment

Functor() : vptr_(0) {}
~Functor()
{
if (vptr_) vptr_->destroy_(*this);
}
Functor(Functor const& src)
{
vptr_ = src.vptr_ ? src.vptr_->clone_(src, *this) : NULL;
}
Functor& operator=(Functor const& src)
{
if (this != &src) {
if (vptr_) vptr_->destroy_(*this);
vptr_ = src.vptr_ ? src.vptr_->clone_(src, *this) : NULL;
}
return *this;
}
// is-empty selector
bool operator!() const { return vptr_ == NULL; }

bool valid() const { return vptr_ != NULL; }

// ctor for static fns and arbitrary functors
template <typename F> explicit Functor(F const& fun)
{
typedef FunctorImpl<F> StoredType;
vptr_ = _init<StoredType>(fun); //assign vptr_ using
}
// ctor for member fns (note: raw ptrs and smart ptrs are equally welcome in pobj)
template <class P, typename MF> explicit Functor(P const& pobj, MF memfun)
{
typedef MemberFnImpl<P, MF> StoredType;
vptr_ = _init<StoredType>(std::pair<P, MF>(pobj, memfun));
}

private:

// initialization helper
template <class T, class V>
typename FunImplBase::VTable* _init(V const& v) //T stands for FunctorImpl or MemberFnImpl, V stands for these contrcutor's argument
{
// gcc obviously complained about the below code due to unused variables
// so I'm removing it for now. As long as the unit tests pass, we should
// be good. -osb
//FunImplBase* pimpl = val_.template init<T>(v);
//pimpl;
val_.template init<T>(v);

// store functorImpl or MemberFnImpl in Stored.Typeless.buffer[]

// MemberFnImpl ctor :T stands for MemberFnImpl<P, MF> V stands for std::pair<P, MF>

// FunctorImpl ctor: T stands for FunctorImpl<F> V stands for F

// throw away pimpl, we don't need it in this implementation
static typename FunImplBase::VTable vtbl =
{
&T::Destroy,
&T::Clone,
&T::Call,
}; // diff T cause diff code instantiation for func _init , diff local static variable vtbl
return &vtbl;
}

Stored val_; //for holding funcImp class instance
typename FunImplBase::VTable* vptr_; // act as the same func as virtual table ptr

public:
// calls
typedef typename dtUtil::TypeAtNonStrict<TList, 0, dtUtil::NullType>::Result Parm1;
typedef typename dtUtil::TypeAtNonStrict<TList, 1, dtUtil::NullType>::Result Parm2;
typedef typename dtUtil::TypeAtNonStrict<TList, 2, dtUtil::NullType>::Result Parm3;
typedef typename dtUtil::TypeAtNonStrict<TList, 3, dtUtil::NullType>::Result Parm4;
typedef typename dtUtil::TypeAtNonStrict<TList, 4, dtUtil::NullType>::Result Parm5;
typedef typename dtUtil::TypeAtNonStrict<TList, 5, dtUtil::NullType>::Result Parm6;
typedef typename dtUtil::TypeAtNonStrict<TList, 6, dtUtil::NullType>::Result Parm7;
#define DoCall(parms) return vptr_->call_(*this, parms);
inline R operator()(ParmsListType const& parms) const { DoCall(parms) }
inline R operator()() const { DoCall(CallParms<TList>::Make()) }

inline R operator()(Parm1 p1) const { DoCall(CallParms<TList>::Make(p1)) }
inline R operator()(Parm1 p1, Parm2 p2) const { DoCall(CallParms<TList>::Make(p1, p2)) }
inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3) const { DoCall(CallParms<TList>::Make(p1, p2, p3)) }
inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) const { DoCall(CallParms<TList>::Make(p1, p2, p3, p4)) }
inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) const { DoCall(CallParms<TList>::Make(p1, p2, p3, p4, p5)) }
inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6) const { DoCall(CallParms<TList>::Make(p1, p2, p3, p4, p5, p6)) }
inline R operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, Parm6 p6, Parm7 p7) const { DoCall(CallParms<TList>::Make(p1, p2, p3, p4, p5, p6, p7)) }

/*CallParams using

//generic pattern

template <class TList, template <class, unsigned int > class Holder, unsigned int i=0> struct InstantiateH{};

//partial instantiation for param TList

template <class T, class U, template<class, unsigned int> class Holder, unsigned int i>

class InstantiateH <TypeList<T,U>, Holder, i>

:public Holder <typename TypeList<T,U>::Head, i>

,public InstantiateH<typename TypeList<T,U>::Tail, Holder, i+1>

{

enum { ordern = i };

typedef Holder <typename TypeList<T,U>::Head, i> LeftBase;

typedef InstantiateH <typename TypeList<T,U>::Tail, Holder, i+1> RightBase;

InstantiateH(typename TypeList<T,U>::Head h, RightBase const &t ):LeftBase(h),RightBase(t){}

InstantiateH(typename Typelist<T,U>::Head h, NullType>:LeftBase(h){}

InstantiateH(typename Typelist<T,U>::Head h>:LeftBase(h){}

InstantiateH(){}

};

//inherited base class partial specializations for termination

template <class TList, template <class ,unsigned int >class Holder, unsigned int i>

class InstantiateH<NullType, Holder, i>

{

InstantiateH(){}

};

template <unsigned int j, typename InstH, unsigned int i = 0> struct InstantiateHAccessor;
template <typename T, typename U, template <class, unsigned int> class Holder, unsigned int i>
struct InstantiateHAccessor<0, InstantiateH<TypeList<T, U>, Holder, i>, i>
{
typedef InstantiateH<TypeList<T, U>, Holder, i> Instance;
typedef typename Instance::LeftBase TargetHolder;
static inline TargetHolder& Get(Instance& h) { return static_cast<TargetHolder&>(h); }
static inline TargetHolder const& Get(Instance const& h) { return static_cast<TargetHolder const&>(h); }
};
template <unsigned int j, typename T, typename U, template <class, unsigned int> class Holder, unsigned int i>
struct InstantiateHAccessor<j, InstantiateH<TypeList<T, U>, Holder, i>, i>
{
typedef InstantiateH<TypeList<T, U>, Holder, i> Instance;
typedef Holder<typename TypeAt<TypeList<T, U>, j>::Result, j+i> TargetHolder;
typedef typename Instance::RightBase RightBase;
static inline TargetHolder& Get(Instance& h) { return InstantiateHAccessor<j-1, RightBase, i+1>::Get(static_cast<RightBase&>(h)); }
static inline TargetHolder const& Get(Instance const& h) { return InstantiateHAccessor<j-1, RightBase, i+1>::Get(static_cast<RightBase const&>(h)); }
};
template <unsigned int j, class Instantiated> inline
typename InstantiateHAccessor<j, Instantiated, Instantiated::ordern>::TargetHolder&
GetH(Instantiated& h)
{
return InstantiateHAccessor<j, Instantiated, Instantiated::ordern>::Get(h);
}
template <unsigned int j, class Instantiated> inline
typename InstantiateHAccessor<j, Instantiated, Instantiated::ordern>::TargetHolder const&
GetH(Instantiated const& h)
{
return InstantiateHAccessor<j, Instantiated, Instantiated::ordern>::Get(h);
}

//struct InstantiateHAccessor<j, InstantiateH<TypeList<T, U>, Holder, i>, i> for static func Get() to return holder

//holder storing the param value and param index of a param in paramList

template <class TList> struct CallParms;

template <>
struct CallParms<TYPELIST_0()>
{
typedef dtUtil::InstantiateH<dtUtil::NullType, dtUtil::TupleHolder> ParmsListType;
static inline ParmsListType Make() { return ParmsListType(); }
};

template <typename P1>
struct CallParms<TYPELIST_1(P1)>
{
typedef dtUtil::InstantiateH<typename dtUtil::CreateTL<P1>::Type, dtUtil::TupleHolder> ParmsListType;
static inline ParmsListType Make(P1 p1)
{
return ParmsListType(p1);
}
};

template <typename P1, typename P2>
struct CallParms<TYPELIST_2(P1, P2)>
{
typedef dtUtil::InstantiateH<typename dtUtil::CreateTL<P1, P2>::Type, dtUtil::TupleHolder> ParmsListType;
static inline ParmsListType Make(P1 p1, P2 p2)
{
return ParmsListType(p1,
typename dtUtil::TailAt<ParmsListType, 0>::Result(p2));
}
};

//... until p7

//generic template

template <typename CallType, typename R, class TList> struct FunctorCall;

//... partial specializations for different numbers
// of arguments of the function types ...

template <typename CallType, typename R>
struct FunctorCall<CallType, R, TYPELIST_0()>
{
typedef dtUtil::InstantiateH<dtUtil::NullType, dtUtil::TupleHolder> ParmsListType;
template <class Fun> static inline R Call(Fun const& fun, ParmsListType& /*parms*/)
{
return fun();
}
template <class PObj> static inline R Call(PObj const& pobj, CallType memfun, ParmsListType& /*parms*/)
{
return ((*pobj).*memfun)();
}
};

template <typename CallType, typename R, typename P1>
struct FunctorCall<CallType, R, TYPELIST_1(P1)>
{
typedef dtUtil::InstantiateH<typename dtUtil::CreateTL<P1>::Type, dtUtil::TupleHolder> ParmsListType;
template <class Fun> static inline R Call(Fun const& fun, ParmsListType& parms)
{
return fun(dtUtil::GetH<0>(parms).value);
}
template <class PObj> static inline R Call(PObj const& pobj, CallType memfun, ParmsListType& parms)
{
return ((*pobj).*memfun)(dtUtil::GetH<0>(parms).value);
}

template <typename CallType, typename R, typename P1, typename P2>
struct FunctorCall<CallType, R, TYPELIST_2(P1, P2)>
{
typedef dtUtil::InstantiateH<typename dtUtil::CreateTL<P1, P2>::Type, dtUtil::TupleHolder> ParmsListType;
template <class Fun> static inline R Call(Fun const& fun, ParmsListType& parms)
{
return fun(
dtUtil::GetH<0>(parms).value,
dtUtil::GetH<1>(parms).value);
}
template <class PObj> static inline R Call(PObj const& pobj, CallType memfun, ParmsListType& parms)
{
return ((*pobj).*memfun)(
dtUtil::GetH<0>(parms).value, //get holder.value for p1
dtUtil::GetH<1>(parms).value); //get holder.value for p2
}
};

//...until p7
};

*/
private:

//copying/destruction and calls implementation

struct FunImpBase //hold three member variable of func pointer , design these to substitute vptr for virtual member func call

{

struct VTable;
struct VTable
{
void (*destroy_)(Functor const&);
VTable* (*clone_)(Functor const&, Functor&);
R (*call_)(Functor const&, ParmsListType);
};
// VTable vtbl_; // not needed here and actually wastes space!

}

template <typename V, class Derived>

// as FunctorImpl base class: V stands for functor, Derived stands for FunctorImpl<functor>

// as MemberFnImpl base class: V stands for std::pair<P,T>, Derived stands for MemberFnImpl<P,T>

struct FunStorageImpl : public FunImplBase //implement Destory, Clone two func
{
V val_;
FunStorageImpl(V const& val) : val_(val) {}
static void Destroy(Functor const& src) { src.val_.template destroy<Derived>(); }
static typename FunImplBase::VTable* Clone(Functor const& src, Functor& dest)
{
Derived const& this_ = src.val_.template get<Derived const>();
return dest._init<Derived>(this_.val_);
}
};

template <typename T>
struct FunctorImpl : public FunStorageImpl<T, FunctorImpl<T> > //implement Call func
{
FunctorImpl(T const& val) : FunStorageImpl<T, FunctorImpl>(val) {}
static R Call(Functor const& src, ParmsListType parms)
{
FunctorImpl const& this_ = src.val_.template get<FunctorImpl const>();
return FunctorCall<T, R, TList>::Call(this_.val_, parms);

//route call to template <class Fun> FunctorCall<T,R,TList>::Call(const Fun&, ParmsListType& params)
}
};
template <class P, typename T>
struct MemberFnImpl : public FunStorageImpl<std::pair<P, T>, MemberFnImpl<P, T> > //implement Call func
{
MemberFnImpl(std::pair<P, T> const& val) : FunStorageImpl<std::pair<P, T>, MemberFnImpl>(val) {}
static R Call(Functor const& src, ParmsListType parms)
{
MemberFnImpl const& this_ = src.val_.template get<MemberFnImpl const>();
return FunctorCall<T, R, TList>::Call(this_.val_.first, this_.val_.second, parms);

//route call to template <class PObj> FunctorCall<T,R,TList>::Call(PObj const& pobj, T memfun, ParmsListType& parms)
}
};
// typeless storage support
struct Typeless //functional class
{
template <typename T> inline T* init1(T* v) { return new(getbuf()) T(v); }
template <typename T, typename V> inline T* init(V const& v) { return new(getbuf()) T(v); }
template <typename T> inline void destroy() const { (*reinterpret_cast<T const*>(getbuf())).~T(); }
template <typename T> inline T const& get() const { return *reinterpret_cast<T const*>(getbuf()); }
template <typename T> inline T& get() { return *reinterpret_cast<T*>(getbuf()); }
void* getbuf() { return &buffer_[0]; }
void const* getbuf() const { return &buffer_[0]; }
unsigned char buffer_[size];
};
template <typename T>
struct ByValue //behaviour class
{
template <typename V> inline static T* init(Typeless& val, V const& v) { return val.template init<T>(v); } // construct T instance from address buffer[0]
inline static void destroy(Typeless const& val) { val.template destroy<T>(); }
inline static T const& get(Typeless const& val) { return val.template get<T>(); }
inline static T& get(Typeless& val) { return val.template get<T>(); }
};
template <typename T>
struct NewAlloc //behaviour class
{
template <typename V> inline static T* init(Typeless& val, V const& v) { return *val.template init<T*>(new T(v)); }

//new T(v) in heap and construct T* from address buffer[0]
inline static void destroy(Typeless const& val) { delete val.template get<T*>(); }
inline static T const& get(Typeless const& val) { return *val.template get<T const*>(); }
inline static T& get(Typeless& val) { return *val.template get<T*>(); }
};
template <typename T>
struct SelectStored //behaviour class
{
// TODO: it seems this is a good place to add alignment calculations
typedef typename dtUtil::Select<
sizeof(T)<=sizeof(Typeless),
ByValue<T>,
NewAlloc<T>
>::Result Type;
};
struct Stored //behaviour class to delegate template func call to template param T class
{
template <typename T, typename V> inline T* init(V const& v) { return SelectStored<T>::Type::init(val_, v); }
template <typename T> inline void destroy() const { SelectStored<T>::Type::destroy(val_); }
template <typename T> inline T const& get() const { return SelectStored<T>::Type::get(val_); }
template <typename T> inline T& get() { return SelectStored<T>::Type::get(val_); }
Typeless val_;
};
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: