Chinaunix首页 | 论坛 | 博客
  • 博客访问: 145784
  • 博文数量: 124
  • 博客积分: 70
  • 博客等级: 民兵
  • 技术积分: 1745
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-24 13:49
文章分类

全部博文(124)

文章存档

2011年(55)

2010年(14)

2009年(30)

2008年(25)

我的朋友

分类: WINDOWS

2010-09-08 15:09:00

boost::bind 有一个很强大的功能,我们看几个例子:
 
将列表中cmdid相同的元素找出来
 AppList_T::iterator it = std::find_if(m_listApp.begin(),m_listApp.end(),
        boost::bind(boost::mem_fn(&_Parent::IsEqualCmdID) ,
        this ,
        strCmdID,
        boost::bind(&AppList_T::value_type::strCmdID , _1)));
    if(it == m_listApp.end())
    {
        g_sdkcomlog.Log(lp_debug ,_T(__FUNCTION__)_T(" no item process %s"),strCmdID);
        return false;
    }
 
这句代码的含义,将那些需要自动下载的插件中, 那些设定了需要检查绑定关系的插件删除.
即仅仅下载那些不需要检查绑定关系的插件.
 
listAutoInstallModule.erase(
   std::remove_if(listAutoInstallModule.begin(),listAutoInstallModule.end() ,   
   !boost::bind(boost::mem_fn( static_cast(&CPluginMgrV2::CheckBindSet)),
    this,
    boost::cref(setBind),
    boost::bind(boost::mem_fn(&CInnerPluginInfo::GetBindSet),
    &m_InnerPluginHelper,
    _1))),
   listAutoInstallModule.end());  
 
 
实际上如果你打开boost的source来看bind,一般来说肯定要晕菜,为什么,一大坨template,一大堆override,
还有很多不大容易直观理解的 辅助模板类.
 
略为看个片段....
 
template    class A1>
    _bi::bind_t, typename _bi::list_av_1::type>
    BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (), A1 a1)
{
    typedef _mfi::BOOST_BIND_MF_NAME(mf0) F;
    typedef typename _bi::list_av_1::type list_type;
    return _bi::bind_t(F(f), list_type(a1));
}
template    class A1>
    _bi::bind_t, typename _bi::list_av_1::type>
    BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) () const, A1 a1)
{
    typedef _mfi::BOOST_BIND_MF_NAME(cmf0) F;
    typedef typename _bi::list_av_1::type list_type;
    return _bi::bind_t(F(f), list_type(a1));
}
.....
 
template    class B1, class B2, class B3, class B4, class B5, class B6, class B7, class B8,
    class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
    _bi::bind_t, typename _bi::list_av_9::type>
    BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7, B8), A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9)
{
    typedef _mfi::BOOST_BIND_MF_NAME(mf8) F;
    typedef typename _bi::list_av_9::type list_type;
    return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9));
}
template    class B1, class B2, class B3, class B4, class B5, class B6, class B7, class B8,
    class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
    _bi::bind_t, typename _bi::list_av_9::type>
    BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7, B8) const, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9)
{
    typedef _mfi::BOOST_BIND_MF_NAME(cmf8) F;
    typedef typename _bi::list_av_9::type list_type;
    return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9));
}
 
为了比较容易来理解它的实现,我尝试从简单的行为来开始模仿它的做法.
为了简单点,我们将呼叫的参数上限定在2.
 
这儿我们不分析基本的函数指针,以及最基本的仿函数用法了,我们直接从,设计一个可以支持0-2个参数的仿函数开始.
 
template
class Functor
{
public:
    R operator()(...)
    {
    }
};
 
写下这个原形,后我大致认为应该有一个类,它有一个R作为返回参数,一个Params作为参数列表;
以及一个operator() 进行仿函数调用.
 
这儿引来了第一个问题, 我们如何设计多个参数,比如0-2个. 当然一种做法是如下:
template
class Functor
{
public:
    R operator()()
    {
    }
    R operator()(Param1 p1)
    {
    }
    R operator()(Param2 p2)
    {
    }
};
 
不过这样带来一个问题,如果支持3参数,那么又得重来了.
 
因此我们首先要解决参数数量问题.
 
我们先许个愿望.
 
template
class Functor
{
};
 
我们希望只有两个模板参数, 第一个表示返回值,第二个表示参数列表.
那么能做到这个要求吗? 可以, 从loki库中也有类似实现.
 
template
class TypeList
{
public:
    typedef T Head;
    typedef U Tail;
};
 
template
class TypeList
{
public:
    typedef T Head;
    typedef EmptyType Tail;
};
 
通过这个模板类,我们抽象定义了一个包含类型的类, 或者我们可以理解template 的ParamList就是这样一个类.
 
为了方便多参数类型定义,我们还定义了如下宏:
#define TYPELIST_1(T) TypeList< T , EmptyType>
#define TYPELIST_2(T1,T2) TypeList< T1 , TYPELIST_1(T2) >
那么我们如何通过ParamList 获取其类型呢?
 
template< int Index, class TL>
class TypeAt;
 
template
class TypeAt<0, TypeList >
{
public:
     typedef head Result;
};
 
template
class TypeAt >
{
public:
    typedef typename TypeAt::Result Result;
};
 
这样我们再回到最初的模板类:
template
class Functor
{
public:
    typedef typename TypeAt<0,ParamList>::Result  Param1;
    typedef typename TypeAt<1,ParamList>::Result  Param2;
 
    // 下面这个能够编译? Praram最终会是啥呢?
    // typedef typename TypeAt<100000,ParamList>::Result  Param;
 
    R operator()()
    {
        return R();
    }
 
    R operator()(Param1 p1)
    {
        return R();
    }
 
    R operator()(Param1 p1,Param2 p2)
    {
        return R();
    }
};
 
Functor f();
 f(1);
Functor f2;
 f2(1,2);
 
ok,这样我们第一步目标完成了.
 
第二个问题很显然, 不可能所有的需要进行呼叫的client都去写这个functor,然后改写内部的operator().
 
也就是说这个functor离最终用户使用还差得远.
 
问题一个个解决吧,我们总得先让用户的ptr或者functor能够传进来.
 
我们假想一下这个形式吧...
 
void p1(int){}
Functor f(p1);
f(1);  // call p1(int)
 
当然如果仅仅是解决这个问题,大可如下:
...
typedef void(*PTR)(int);
class Functor
{
...
    Functor(PTR p)
....
}
 
问题是如果这样做了之后,就太没有通用性了.还不如自己写...
 
那么是不是直接引入一个模板参数即可呢?
template
class Functor
{
public:
    typedef typename TypeAt<0,ParamList>::Result  Param1;
    typedef typename TypeAt<1,ParamList>::Result  Param2;
 
    Functor(Ptr p) : m_p(p){}
 
    R operator()()
    {
        return m_p();
    }
 
    R operator()(Param1 p1)
    {
        return m_p(p1);
    }
 
    R operator()(Param1 p1,Param2 p2)
    {
        return m_p(p1,p2);
    }
 
private:
    Ptr  m_p;
};
 
然后
Functor f(p1);
f(1);
 
Functor f(p2);
f(1,2);
 
也能用,不过这个缺点就是我必须明确提供类型, 当然如果不算这个缺点,倒也还可以.
 
我们继续优化, 我们希望这个ptr是能够被推导的....
 
template
class Functor
{
public:
    typedef typename TypeAt<0,ParamList>::Result  Param1;
    typedef typename TypeAt<1,ParamList>::Result  Param2;
 
    template
    Functor(Ptr p) {.... 晕菜了.... Ptr 外面不知道}
 
    R operator()()
    {
        return m_p();
    }
 
    R operator()(Param1 p1)
    {
        return m_p(p1);
    }
 
    R operator()(Param1 p1,Param2 p2)
    {
        return m_p(p1,p2);
    }
 
private:
    };
 
这样写能够编译,不过很显然有问题,因为内层的模板参数外面的functor不知道.
 
那how?? 显然将m_p 也移动到内层...,还是设计模式那套,搞个间接...
 
我们定义一个间接类,叫做FuncHandler; 这个间接类,必须知道functor带有的R,Params 也得知道
用户的PTR ,那么一种做法...
 
如下...
 
template
class FuncHanlder
{
public:
   
};
 
这样岂不是回到解放前...
 
想想看functor如何才能将自己的类型传给funchandler??
 
赫赫,可以是派生也可以是聚合之类, 不过有一点是确定的,即functor不能直接定义funchander,因为
缺少PTR这个类型. 如果写一下代码你会发现....
 
 
class Functor : public FuncHanlder  xx,yy该填写啥呢?  如果我知道,何必烦劳你呢?
 
如果
 
class functor
{
    funchandler f;   xx,yy该填写啥呢?  如果我知道,何必烦劳你呢?
    funchandler* f;  xx,yy该填写啥呢?  如果我知道,何必烦劳你呢?
};
 
因此到了这儿,显然还得间接以下,c++中能够支持这类间接的, 这儿得请出 虚函数来了,只有它,才能让我先定义一个,然后呼叫真实的handler.
 
或者说c++存在这样一种特殊的行为,即构造函数,或者其他模板成员函数的模板类型,离开了此函数此模板类类型就丢失了. 但是如果我们定义一个接口,用这个接口获取使用这个类型事例化的一个实例,那么我们虽然丢失了类型信息,但是我们还是保留了可以呼叫这个类型实例的可能性,而这个就是虚函数机制.
 
 
 
也就是说我们得定义一种行为,这个行为叫做呼叫, 然后这个行为可以由具体的handler来实现....
 
 
template
class IFuncHandler
{
public:
    virtual R operator()() = 0;
    virtual ~IFuncHandler(){}
 
    // 其他的我们就省略了
};
 
template
class IFuncHandler
{
public:
    virtual R operator()(Param) = 0;
    virtual ~IFuncHandler(){}
 
    // 其他的我们就省略了
};
 
template
class IFuncHandler
{
public:
    virtual R operator()(Param1,Param2) = 0;
    virtual ~IFuncHandler(){}
 
    // 其他的我们就省略了
};
 
然后我们再来定义 funchandler..
 
template
class FuncHandler : public IFuncHandler
      <
       typename _Functor::ReturnType,
       typename _Functor::ParamList
      >
{
public:
 typedef typename _Functor::ReturnType R;
 typedef typename _Functor::Param1 Param1;
 typedef typename _Functor::Param2 Param2;
 
 FuncHandler(PTR p)
 {
  m_p = p;
 }
 virtual ~FuncHandler()
 {
 }
 /*virtual */ R operator()()   // 这儿的virtual 不能明显写出来,否则就阻止了编译器对于模板的容错处理, 即我不用那么你只要语法合理,语义不对编译器是不管的
 {
  return m_p();
 }
  /*virtual */ R operator()(Param1 p1)
 {
  return m_p(p1);
 }
  /*virtual */ R operator()(Param1 p1,Param2 p2)
 {
  return m_p(p1,p2);
 }

private:
 PTR m_p;
};
 
 
通过上面的 类型丢失分析,也知道handler需要重写,以聚合一个impl的指针,然后在构造函数中实例化真实的实例,下面就是代码.
 
template
class Functor
{
public:
 typedef R Result;
 typedef typename TypeAt<0,tl>::Result Param1;    // funchandler 演绎的
 typedef typename TypeAt<1,tl>::Result Param2;
 typedef typename TypeAt<1000,tl>::Result Param4;
 typedef R ReturnType;
 typedef tl ParamList;
 template
 Functor(PTR p)
 {   
   m_spHandlerImp.reset(new FuncHandler(p));
   // 出了花括弧PTR类型就丢失了,但是 m_spHandlerImpl 已经拿到了它的实现,这也是c++能做到的
 }
 
// 下面这几个函数,尽管实际spHandlerImp 并不一定有这么多实现,但是非虚的模板函数依然令编译器
// 可以放弃语法正确但是语义不符的函数通过
 R operator()()
 {
  return m_spHandlerImp->operator ()();
 }
 R operator()(Param1 p1)
 {
  return m_spHandlerImp->operator ()(p1);
 }
 R operator()(Param1 p1,Param2 p2)
 {
  return m_spHandlerImp->operator ()(p1,p2);
 }
private:
 typedef IFuncHandler FuncHandlerImp;   // 这句话是关键,定义了一个抽象接口
 std::auto_ptr m_spHandlerImp;
};
 
下面是client代码,也工作的很正常..
Functor f(p1);
 f(1);
 Functor f2(p2);
 f2(1,2);

Functor f0(p0);  // 还是要输入一个emptytype 表示无参数
 f0();
 
实际上上面client代码的p0,p1,p2 你即可以通过函数指针,也可以通过传入一个对象实例的方法来调用,
这个就是模板推导的威力,PTR可以自行推导出你是ptr还是functor.
 
 
代码到了这儿, 我们再来看看这个functor,我们还需要它支持啥?
 
对了,我们要支持成员函数,即 R (M::*)(Params) 这个类型..
 
 
让我们先来支持通过对象来呼叫...
 
那么仔细想一下第一步该如何修改呢?
 
我们发现只是需要支持一个类型参数PTR,现在需要支持ObjectType or PointerType 那么我们貌似应该在某个类中间增加一个Type , Functor or FunctorHandler 呢?
 
判别应该有依据, Functor 现在接受返回值和参数列表并且拥有一个impl 指向一个具体的handler,即从设计模式上,它已经拥有了一层间接的能力, 因此我们如果修改fuctor,那么只能重新一个Functor;
还有一种作法是我们再写一个handler<_Functor,objtype,ptr> ;
 
现在我们比较一下,如果我们写一个functor, 那么我们还是得再写一个hanlder合他匹配;
 
而如果我们新写一个handler,那么functor只要增加结构构造函数可以接受新的参数即可,因此选择是添加新的handler,利用多态来由functor转发...
 
 

template
class MemFuncHandler : public IFuncHandler
      <
       typename _Functor::ReturnType,
       typename _Functor::ParamList
      >
{
public:

 typedef typename _Functor::ReturnType R;
 typedef typename _Functor::Param1 Param1;
 typedef typename _Functor::Param2 Param2;
 

 MemFuncHandler(const ObjectType& obj,PTR p)
 {
  m_obj = obj;
  m_p = p;
 }

 virtual ~MemFuncHandler()
 {
 }

 R operator()()
 {
  return (m_obj.*m_p)();
 }

 R operator()(Param1 p1)
 {
  return (m_obj.*m_p)(p1);
 }

 R operator()(Param1 p1,Param2 p2)
 {
  return (m_obj.*m_p)(p1,p2);
 }


private:
 ObjectType m_obj;
 PTR m_p;
};

接下来我们修改functor...
template
 Functor(ObjectType Obj, MemFuncPtr ptr)
 {
   m_spHandlerImp.reset(new MemFuncHandler(Obj,ptr));
 }
 
仅仅只要添加这样一个构造函数即可....
 
// c++ 成员函数测试,采用对象呼叫
 {
  testfunctor0 p0;
  Functor f0(p0,&testfunctor0::test);
  f0();
  testfunctor1 p1;
  Functor f(p1,&testfunctor1::test);
  f(1);
  testfunctor2 p2;
  Functor f2(p2,&testfunctor2::test);
  f2(1,2);
 }
 
这样就达到了要求,然后再支持指针...
 
// 利用override 而不是partial specialization
 // 因为模板函数,所以编译器会选择最匹配的函数
 template
 Functor(ObjectType* Obj, MemFuncPtr ptr)
 {
   m_spHandlerImp.reset(new MemFuncHandler(Obj,ptr));
 }
 // 成员函数偏特化目前的c++还不支持
 /*template
 Functor(ObjectType* Obj, MemFuncPtr ptr)
 {
   m_spHandlerImp.reset(new MemFuncHandler(Obj,ptr));
 }*/
 
 
添加新的handler
template
class MemFuncHandler<_Functor,ObjectType*,PTR>  : public IFuncHandler
      <
       typename _Functor::ReturnType,
       typename _Functor::ParamList
      >
{
public:
 typedef typename _Functor::ReturnType R;
 typedef typename _Functor::Param1 Param1;
 typedef typename _Functor::Param2 Param2;
 
 MemFuncHandler(ObjectType* obj,PTR p)
 {
  m_obj = obj;
  m_p = p;
 }
 virtual ~MemFuncHandler()
 {
 }
 R operator()()
 {
  return ((*m_obj).*m_p)();
 }
 R operator()(Param1 p1)
 {
  return ((*m_obj).*m_p)(p1);
 }
 R operator()(Param1 p1,Param2 p2)
 {
  return ((*m_obj).*m_p)(p1,p2);
 }

private:
 ObjectType* m_obj;
 PTR m_p;
};
// c++ 成员函数测试,采用指针呼叫
 {
  testfunctor0 p0;
  Functor f0(&p0,&testfunctor0::test);
  f0();
  testfunctor1 p1;
  Functor f(&p1,&testfunctor1::test);
  f(1);
  testfunctor2 p2;
  Functor f2(&p2,&testfunctor2::test);
  f2(1,2);
 }
 
到了这儿,一个比较接近于(其实还很远)boost::bind的functor已经出现了...
 
到了,这儿我们发现一个问题,当然我们暂时先不考虑const ,volatile, 传入的objptr 是smartptr的这些琐碎的检查, 至少用起来还是很麻烦,即你必须指定参数类型, 这个使用起来就很麻烦.
 
另外一个问题是还不支持参数的绑定,即参数是在调用时候一次性指定的,而不能像boost那样,通过_1,_2 等,留待实际运行时候再和实际参数绑定.
 
这儿我们先尝试解决第一个问题...
先来看一个简单的事实...
template
R test()
{
 return R();
}

int _tmain(int argc, _TCHAR* argv[])
{
 int i = test();
 return 0;
}
// 1>d:\template\test1\test1\test1.cpp(30) : error C2783: “R test(void)”: 无法为“R”推导 模板 参数
 
即c++中, 目前还不能通过对返回值进行模板参数演绎,因此必须自己指定,这也是boost::bind
一般来说我们使用boost::bind时候一个模板参数还是需要携带的...
 
我们还得知道一个事实,即c++还不支持对构造函数进行实参演绎,即...
 
template< typename T>
class ctest2
{
public:
    ctest2(T a)
    {
    }
};
 
int i;
ctest2 a(i); // 是推导不出T = int
// ctest2”: 使用类 模板 需要 模板 参数列表
 
因此我们之前的代码通过...
template
 Functor(PTR p)
 {
   m_spHandlerImp.reset(new FuncHandler(p));
 }
 template
 Functor(ObjectType Obj, MemFuncPtr ptr)
 {
   m_spHandlerImp.reset(new MemFuncHandler(Obj,ptr));
 }
 
想以此种方式来推导ParamList 就不行了...
 
我的期望可能是...
functor task = make_functor(ptr, param);
task(param);
 
这样使用起来就非常方便了....
因此显然,需要引入一组模板函数,实际上boost也是这么做的,本文开头那一大坨东西就是函数定义..
 
 
 
因此我们尝试能够以只提供一个返回值得类型,解决c函数的调用.....
 
functor task = make_functor(ptr, param);
 
我们还是一步一步来,如果我们仅仅...
make_functor(ptr, param)();
make_functor(ptr, param)(0);
 
这样呢?  相当于boost::bind 立刻发起调用, task = make_functor 这种模式留待研究绑定的时候来讲...
 
这样我们任务明确了, 也知道了c++的两个限制..., 因此我们很容易制定出一组函数...
 
template
Functor make_functor(R (*p)())
{
 return Functor(p);
}
template
Functor make_functor(R (*p)(param1))
{
 return Functor(p);
}
template
Functor make_functor(R (*p)(param1,param2))
{
 return Functor(p);
}
 
 std::cout<< "类型推导,c函数测试,不带绑定" << std::endl;
 // 类型推导,c函数测试
 {
  make_functor(p0)();
  make_functor(p1)(1);
  make_functor(p2)(1,2);
 }
 
有了这个开始,我们继续深入以下,可以支持成员函数的绑定...
 
template
Functor make_functor(T* objptr,R (T::*p)())
{
 return Functor(objptr,p);
}
template
Functor make_functor(T* objptr,R (T::*p)(param1))
{
 return Functor(objptr,p);
}

template
Functor make_functor(T* objptr,R (T::*p)(param1,param2))
{
 return Functor(objptr,p);
}
 
std::cout<< "类型推导,成员函数测试,不带绑定" << std::endl;
 // 类型推导,c函数测试
 {
  testfunctor0 p0;
  make_functor(&p0,&testfunctor0::test)();
  testfunctor1 p1;
  make_functor(&p1,&testfunctor1::test)(1);
  testfunctor2 p2;
  make_functor(&p2,&testfunctor2::test)(1,2);
 }
 
现在我们尝试来研究第二个问题,即如何绑定;以及如何在使用的时候可以存储我们的呼叫;
// 如下代码显示我们希望能够类型自动推导情况下,保存呼叫
functor task = make_functor(ptr, param);
task(1,2);
 
// 展示了如何支持绑定
functor task = make_functor(ptr, param, 1 /* first param */);
task(2 /* second param */);
 
 
为了将问题简化,我们先尝试bing1st这类简单的应用.
达到效果  bind1st(functor, 1)(2);  // functor include 2 param function call
 
我自己的思路,当写到这儿的时候,特别想扩展make_functor ,比如...
template
Functor make_functor(R (*p)(param1),pararm1 p1)
{
 return Functor(p,p1); // ???
}
 
但是很快发现, 如果这样顺着这个思路下去, 那么functor 内需要存储param,而且还要判定用户传进来几个,
因此很快发现这条路不太好走.
这儿实际上我还是借鉴了设计新思维上的代码,以及stl的bindfirst
...
 
从用户的使用角度来说,或许是这样的代码:
  bindfirst(cmd,param1)
 
这个东西本身也是个functor,可以放入比如for_each, find_if 等使用.
 
即行为上要求binder也是一个functor,也支持operator(), 而这些行为funcimpl已经定义,因此可以考虑复用..
 
 
从这个虚拟的调用来看, cmd这个地方,到底是直接支持PTR, 普通的class functor还是支持高级的我们本文定义的functor呢?
 
如果是前者,那么和之前的make_functor就没什么区别了;
 
再考虑到我们先要剥离functor 的第一个参数,然后又要返回一个functor而这个cmd还有剩余的参数,
这个貌似很自然我们就应该利用functor了, 因为functor已经很好的定义了参数的类型,以及数量,我们是比较容易推导第一个参数以及剩余参数的...
 
下面另外一个问题是我们如何能够输入一个functor,然后返回这个functor的少了第一个参数的functor呢?
显然bind1st这个函数需要内部实例化一个functor, 上面的分析已经说了, 由于functor已经很好的定义了类型,因此我们是比较容易推导的....
 
来看...
 
template<_functor>
??returntype?? 
bindfirst(_functor fun, typename _functor::Param1 bound1)
{
    typedef typename _functor::returntype returntype;
    ?? 我们该如何实例化一个functor呢???
}
 
上面的代码是我基本上立刻可以想到的, 即第一个参数,返回类型是很容易推导的...
但是返回functor如何推导出来? 如何实例化返回functor??
 
 
 
我们来想一下,我们现在的functor的几个构造函数:
1. 默认copy构造函数,我们没有提供
2. 模板化的支持输入PTR,objptr直接构造的.
 
第一种构造显然无法实例化我们需要的返回functor.
第二种貌似也不行,不过再想一下,对看看代码:
 
template
 Functor(ObjectType Obj, MemFuncPtr ptr)
 {
   m_spHandlerImp.reset(new MemFuncHandler(Obj,ptr));
 }
 // 利用override 而不是partial specialization
 // 因为模板函数,所以编译器会选择最匹配的函数
 template
 Functor(ObjectType* Obj, MemFuncPtr ptr)
 {
   m_spHandlerImp.reset(new MemFuncHandler(Obj,ptr));
 }
 // 成员函数偏特化目前的c++还不支持
 /*template
 Functor(ObjectType* Obj, MemFuncPtr ptr)
 {
   m_spHandlerImp.reset(new MemFuncHandler(Obj,ptr));
 }*/
 
上述红颜色的字体,应该说从bind1st的输入参数我们是很难拿到ptr or objptr. 即使拿到了,也会破坏目前的封装. 但是我们再仔细看看,实际上第二种构造函数绕了一大圈就是要设置一个 handlerimpl, 那么bind1st能否直接提供呢?
 
我们直接看stl的bind1st实现,看看有否启发?
 
templateFn2,
 class _Ty> inline
 binder1st<_Fn2> bind1st(const _Fn2& _Func, const _Ty& _Left)
  { // return a binder1st functor adapter
  typename _Fn2::first_argument_type _Val(_Left);
  return (std::binder1st<_Fn2>(_Func, _Val));
  }
template_Fn2>
 class binder1st
  : public unary_function   typename _Fn2::result_type>
{
....
}
 
我们可以观察,stl定义了一个 binder1st,而这个类,又从一个类型包装类中派生过来,同时这个类的模板参数貌似还同std::bind1st一样...
 
有啥启发呢?
 
我觉得,我们也可以定义一个binder1st, 同时这个类派生自handlerimpl(这一步很关键), 这样我们以
functor作为模板参数给这个类, 同时根据前面的讨论已经知道了,通过一个functor是比较容易推倒出
返回类型, 第一个参数,剩余参数的. 这样貌似这个问题就可以解决了...
 
剩下的问题是如何解决bind1st的返回类型...
这个问题其实已经相对简单了...,因为不需要实例化,只要一个类型就比较简单了....
 
定义一个bind1st_traits...
 
 
template
class bind1st_traits
{
public:
 typedef typename _Functor::ReturnType R;
 typedef typename _Functor::ParamList::Tail tl;
 typedef Functor FunctorType;  // 这个就少了一个参数
 typedef IFuncHandler FuncHandlerType;
};
 
再来看看binder
 
template
class Bind1stHandler : public IFuncHandler
      <
       typename _Functor::ReturnType,
       typename _Functor::ParamList::Tail    // 合理瘦身,减少了一个参数
      >
{
public:
 typedef _Functor _Fun;
 typedef typename _Functor::ReturnType R;
 typedef typename _Functor::Param1 bound1;
 typedef IFuncHandler
      <
       typename _Functor::ReturnType,
       typename _Functor::ParamList::Tail
      > _impl;
 
 typedef typename _impl::Param1 Param1; // 实际上是原始functor的第二个参数
 typedef typename _impl::Param2 Param2; // 实际上是原始functor的第3个参数
 Bind1stHandler(_Fun fun,bound1 p1) : m_fun(fun)
 {  
  m_p1 = p1;
 }
 R operator()()
 {
  return m_fun(m_p1);
 }
 R operator()(Param1 p1)
 {
  return m_fun(m_p1,p1);
 }
 R operator()(Param1 p1,Param2 p2)
 {
  return m_fun(m_p1,p1,p2);
 }
private:
 _Fun m_fun;
 Param1 m_p1;
};
最后是bind1st...
 
template
typename bind1st_traits<_Functor>::FunctorType   // 返回瘦身后的functor
bind1st(_Functor fun, typename _Functor::Param1 bound)
{
 typedef bind1st_traits<_Functor>::FunctorType ReturnFunctor;
 typedef typename _Functor::ReturnType R;
 typedef bind1st_traits<_Functor>::FuncHandlerType FuncHandlerType;
 
  // 下面这句话创建了一个binder,而binder本身又派生自IHandlerImpl
  FuncHandlerType* pReturnFunctor = new Bind1stHandler<_Functor>(fun,bound);
 return ReturnFunctor(pReturnFunctor);
}
 
最后为functor添加一个构造函数...
template <>
 Functor(FuncHandlerImp* _imp)
 {
  m_spHandlerImp.reset(_imp);
 }
 
最后看看代码
std::cout<< "绑定测试 bind1st" << std::endl;
 // 绑定测试
 {
  testfunctor1 p1;
  Functor f1 = make_functor(&p1,&testfunctor1::test);
  bind1st(f1,1)();
  testfunctor2 p2;
  Functor f2 = make_functor(&p2,&testfunctor2::test);
  bind1st(f2,1)(2.0);
 }
 
 
写到这儿,我觉得最后就差如何以一种统一的形式来存储functor,且不需要用户直接输入类型.....
 
这个或许就是我们的愿望.....
functor task = make_functor(ptr, param);
 
它体现了:
1. 用户不需要明确提供类型
2. 任何的functor均能够被某种对象持有,而这个对象可以后续进行呼叫
 
就像task_pool::task 那样....
 
这个问题在c++设计新思维中实际上并没有直接描写,loki中貌似也没有.....
 
这儿我们还是参考下xxx工程中的task_pool::task 的类型定义,
 
function task = boost::bind...
这样就可以另 function 可以表示任何R = void的task closure...
 
结合我们之前解决的最后一个问题,就是通过bind 我们可以控制最终调用时候参数的数量,什么意思呢?
 
就是假定我们最终需要调用的函数具有n个参数,那么一旦我们在bind的时候将n各参数都提供了;
那么最终这个 functor被调用的时候,其仅仅只需要提供0ge参数.
 
这样就是说,理论上我们如果原因另R 始终= void,
那么我们是有可能通过定义一个function 对象,而这个对象实际上只处理void (), 这种类型的函数;
 
来看这个我们之前测试过的实例, 看红色部分
testfunctor1 p1;
  Functor f1 = make_functor(&p1,&testfunctor1::test);
  bind1st(f1,1)();
 
即最终我们是能够将调用体现为  xxx() ,这个固定形式的,而xxx 在这儿是内部一个functor.
 
那问题转换为,我们有能力定义一个function ,而这个functor 支持一种内在的  operator(),
forward调用内部的 functor()吗?
 
这个问题的解决,实际的实质是, 我们的bind函数实际上返回了一个functor ,那么function如何存储这个变化的 functor ,且供之后的invoke或者operator()调用呢?
 
答案是确定的.和我们之前的内容所写的,构造函数出去后类型丢失的问题一样,貌似我们应该定义一个抽象的中间对象,比如这个对象只有一个invoke方法,返回值=R, 而这个类型的构造函数可以接受一个bind返回的functor...
 
这样做就意味着所有的binder都需要派生自ixxxinvoker接口....
 
这样做貌似不够好....
 
 
到了这儿,我们需要参考一下boost::function<> 是如何实现和处理的.
 
阅读(649) | 评论(0) | 转发(0) |
0

上一篇:ATL & STL & c++ 问题

下一篇:学习boost::function

给主人留下些什么吧!~~