实现 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;
}