实现 STL 的 BindFirst 功能
假设有个 Functor 取两个整数作为参数,你想将其中一个整数绑定为固定值,只让另一个变化。绑定会产生出一个”只取单一整数“的 Functor,如下:
void f() { // Define a Functor of two arguments Functor<void, TYPELIST_2(int, int)> cmd1(something); // Bind the first argument to 10 Functor<void, TYPELIST_1(int)> cmd2(BindFirst(cmd1, 10)); // Same as cmd1(10,20) cmd2(20); Functor<void> cmd3(BindFirst(cmd2,10)); // Same as cmd1(10, 30) cmd3(30); }
绑定不但可以保存”可调用体“,还可以保存它的部分参数并足部降低调用时刻所需的环境需求。这大大提高了 Functor 的表达能力,因为它可以让你包装函数和参数,无需添加作为”粘胶“之用的代码。
template <class Incoming> class BinderFirst : public FunctorImpl < typename Incoming::ResultType, typename Incoming::ParmList::Tail > { typedef Functor < typename Incoming::ResultType, typename Incoming::ParmList::Tail > Outgoing; typedef typename Incoming::Parm1 Bound; typedef typename Incoming::ResultType ResultType; public: BinderFirst(const Incoming& fun, Bound bound) : fun_(fun), bound_(bound) {} BinderFirst* Clone() const { return new BinderFirst(*this); } ResultType operator()() { return fun_(bound_); } ResultType operator()(typename Outgoing::Parm1 p1) { return fun_(bound_, p1); } ResultType operator()(typename Outgoing::Parm1 p1, typename Outgoing::Parm2 p2) { return fun_(bound_, p1, p2); } private: Incoming fun_; Bound bound_; }; namespace Private { template <class Fctor> struct BinderFirstTraits; template <typename R, class TList> struct BinderFirstTraits < Functor<R, TList> > { typedef Functor<R, TList> OriginalFunctor; typedef typename TL::Erase < TList, typename TL::TypeAt<TList, 0>::Result > ::Result ParmList; typedef typename TL::TypeAt<TList, 0>::Result OriginalParm1; typedef Functor<R, ParmList> BoundFunctorType; typedef typename BoundFunctorType::Impl Impl; }; } template <class Fctor> typename Private::BinderFirstTraits<Fctor>::BoundFunctorType BindFirst(const Fctor& fun, typename Fctor::Parm1 bound) { typedef typename Private::BinderFirstTraits<Fctor>::BoundFunctorType Outgoing; return Outgoing(auto_ptr<typename Outgoing::Impl>(new BinderFirst<Fctor>(fun, bound))); } const char* Fun(int i, int j) { cout << "Fun(" << i << "," << j << ") called" << endl; return "0"; } int main() { Functor<const char*, TYPELIST_2(int, int)> f1(&Fun); Functor<string, TYPELIST_1(double)> f2(BindFirst(f1, 10)); f2(15); return 0; }