S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

C++中的通用Closure

Posted on 2011-04-06 05:01 S.l.e!ep.¢% 阅读(955) 评论(0)  编辑 收藏 引用 所属分类: C++
在这篇文章里面,我介绍一下如何自己实现一个闭包,方便进行C++的类函数回调。该闭包能够接受任意类以及类成员做参数。


* 闭包概念
来源于大名鼎鼎的wikipedia:
In computer science, a closure is a function that is evaluated in an
environment containing one or more bound variables. When called, the function can access these variables.

就是说闭包绑定了一个函数以及该函数调用发生需要的所有参数。当闭包被调用的时候,相当于函数被调用,而且可以访问绑定的参数。


* 第一步,能接受任意类型的类对象
这是第一个实现
<code>
template<typename T>
class Closure {
  typedef void (T::Func)();
  public:
    Closure(T* obj, Func f):
      obj_(obj), f_(f) {
    }

    void Run() {
      (obj_::*f_)();
    }

 private:
   T *obj_;
   Func *f_;
};
</code>

使用起来
<code>
class MyClass {
 public:
  void PrintName() { cout << "MyClass"; }
};

MyClass obj;
Closure<MyClass> closure(obj, &MyClass::PrintName);
closure.Run();
</code>

看起来不错,是吧:-)
但是还不能绑定参数呢。。我们来解决这个问题,让他能绑定一个参数先。


* 第二步,能绑定一个任意类型参数
<code>
template<typename T, typename Arg>
class Closure {
  typedef void (T::Func)(Arg);
  public:
    Closure(T* obj, Func f, Arg a):
      obj_(obj), f_(f), a_(a) {
    }

    void Run() {
      (obj_::*f_)(a_);
    }

 private:
   T *obj_;
   Func *f_;
   Arg a_;
};
</code>

使用方法
<code>
class MyClass {
 public:
  void PrintName(const string& name) { cout << name; }
};

MyClass obj;
Closure<MyClass, string> closure(obj, &MyClass::PrintName, "MyName");
closure.Run();
</code>

哈哈,很好!现在可以绑定参数罗~~
那怎么可以绑定两个参数呢?嘿嘿,自己想吧~

现在这个使用方法我觉得很难看,既然调用方法都是统一的void
Run(),我们应该可以让它使用起来更简单. 而且如果我要把两个不同的
closure传给某个函数就做不到。
比如:
<code>
class MyClass {
 public:
  void PrintName(const string& name) { cout << name; }
};

class MyClass_2 {
 public:
  void PrintValue(int val) { cout << val; }
}

// 这个函数怎么写才能让两个不同的closure都可以传进来?
void func(???* closure) { closure->Run(); }

MyClass obj;
Closure<MyClass, string> closure1(obj, &MyClass::PrintName, "MyName");
MyClass_2 obj2;
Closure<MyClass_2, int> closure2(obj, &MyClass::PrintValue, 11);
closure.Run();
</code>

好吧,干活儿!

* 第三步,使用起来更简单的Closure
<code>
// 基类;
class Closure {
  public:
    virtual void Run() = 0;
};

// 实现支持一个参数的Closure;
template<typename T, typename Arg>
class OneArgClosure: public Closure {
  typedef void (T::Func)(Arg);
  public:
    Closure(T* obj, Func f, Arg a):
      obj_(obj), f_(f), a_(a) {
    }

    virtual void Run() {
      (obj_::*f_)(a_);
    }

 private:
   T *obj_;
   Func *f_;
   Arg a_;
};

// 辅助函数
Template<typename T, typename Arg>
Closure* NewClosure((T* obj, Func f, Arg a) {
  return OneArgClosure(obj, f, a);
}
</code>

使用起来简单多啦
<code>
class MyClass {
 public:
  void PrintName(const string& name) { cout << name; }
};

MyClass obj;
Closure* closure = NewClosure(obj, &MyClass::PrintName, "MyName");
closure->Run();
delete closure;
</code>


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理