程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> boost::bind的簡單實現,boostbind實現

boost::bind的簡單實現,boostbind實現

編輯:C++入門知識

boost::bind的簡單實現,boostbind實現


  在上一篇blog中簡單的實現了boost::function,支持帶有2個參數的函數/函數指針,函數對象,函數適配器/bind類,以及帶有1個參數的成員函數指針。

  本文接著來介紹如何實現一個簡單的boost::bind。

  基本目標如下:

  1、支持接收0個參數的函數/函數指針,函數對象。

  2、支持接收1個參數的函數/函數指針,函數對象。

  3、支持接收2個參數的函數/函數指針,函數對象。

  首先,解決占位符的問題:

 1 namespace
 2 {
 3 
 4 struct Placeholders1
 5 {
 6 } _1;
 7 
 8 struct Placeholders2
 9 {
10 } _2;
11 
12 }

使用匿名namespace的原因是防止不同編譯單元中的命名沖突, 讓占位符對象只在其所在的編譯單元中可見。

  在boost::bind源碼中主要是通過2個list表維持各種相關信息。一個bindlist表維持了bind接收的綁定參數,包括占位符,用戶傳入的變量等。一個calllist維持了調用bind返回的對象時所傳入的參數信息。它們的通過繼承層次的方式來表現的。

  下面這個繼承層次的每一個類都要作為對應的bindlist和calllist層次中的基類,它們分別保存了bind接收的綁定參數信息(用戶傳入的變量,占位符),以及調用bind返回的對象時所傳入的參數信息。

 1 class Base0
 2 {
 3 };
 4 
 5 template<typename T1>
 6 class Base1 : public Base0
 7 {
 8 public:
 9     Base1(T1 data1)
10         : data1_(data1)
11     {
12     }
13 
14 protected:
15     T1 data1_;
16 };
17 
18 template<typename T1, typename T2>
19 class Base2 : public Base1<T1>
20 {
21 public:
22     Base2(T1 data1, T2 data2)
23         : Base1<T1>(data1), data2_(data2)
24     {
25     }
26 
27 protected:
28     T2 data2_;
29 };

  接著,就是所謂的calllist的實現了。它們的基類將保存調用bind返回的對象時所傳入的參數信息。

 1 class CallList0 : public Base0
 2 {
 3 public:
 4     template<typename _T>
 5     _T operator[](_T arg)
 6     {
 7         return arg;
 8     }
 9 };
10 
11 template<typename T1>
12 class CallList1 : public Base1<T1>
13 {
14 public:
15     CallList1(T1 data1)
16         : Base1<T1>(data1)
17     {
18     }
19 
20     T1 operator[](Placeholders1 arg1)
21     {
22         return Base1<T1>::data1_;
23     }
24 
25     template<typename _T>
26     _T operator[](_T arg)
27     {
28         return arg;
29     }
30 
31 };
32 
33 template<typename T1, typename T2>
34 class CallList2: public Base2<T1, T2>
35 {
36 public:
37     CallList2(T1 data1, T2 data2)
38         : Base2<T1, T2>(data1, data2)
39     {
40     }
41 
42     T1 operator[](Placeholders1 arg1)
43     {
44         return Base2<T1, T2>::data1_;
45     }
46 
47     T2 operator[](Placeholders2 arg2)
48     {
49         return Base2<T1, T2>::data2_;
50     }
51 
52     template<typename _T>
53     _T operator[](_T arg)
54     {
55         return arg;
56     }
57 };

  然後,我們來看看bindlist,它們的基類主要保存了bind接收的占位符、參數信息。

 1 class BindLinst0 : public Base0
 2 {
 3 public:
 4     template<typename Func>
 5     void operator()(Func func)
 6     {
 7         func();
 8     }
 9 };
10 
11 template<typename T1>
12 class BindList1 : public Base1<T1>
13 {
14 public:
15     BindList1(T1 data1)
16         : Base1<T1>(data1)
17     {
18     }
19 
20     template<typename Func, typename Call>
21     void operator()(Func func, Call call)
22     {
23         func(call[Base1<T1>::data1_]);
24     }
25 };
26 
27 template<typename T1, typename T2>
28 class BindList2 : public Base2<T1, T2>
29 {
30 public:
31     BindList2(T1 data1, T2 data2)
32         : Base2<T1, T2>(data1, data2)
33     {
34     }
35 
36     template<typename Func, typename Call>
37     void operator()(Func func, Call call)
38     {
39         func(call[Base2<T1, T2>::data1_], call[Base2<T1, T2>::data2_]);
40     }
41 };

  接下來就是bind函數所返回的對象了,相信童鞋們可以想象的到,這個對象中應該主要保存的是bind函數接收的參數信息咯,並且他還保存了所注冊的函數。

 1 template<typename Func, typename Bind>
 2 class BindImpl
 3 {
 4 public:
 5     BindImpl(Func func, Bind bindlist)
 6         : func_(func), bindlist_(bindlist)
 7     {
 8     }
 9 
10     void operator()()
11     {
12         bindlist_(func_);
13     }
14 
15     template<typename T1>
16     void operator()(T1 data1)
17     {
18         bindlist_(func_, CallList1<T1>(data1));
19     }
20 
21     template<typename T1, typename T2>
22     void operator()(T1 data1, T2 data2)
23     {
24         bindlist_(func_, CallList2<T1, T2>(data1, data2));
25     }
26 
27 protected:
28     Func func_;
29     Bind bindlist_;
30 };

  如此,基本的輪廓就已經出來了。bind函數返回一個BindImpl對象,裡面保存了注冊的函數和bind接收的占位符、參數信息。當我們調用這個對象的時候,會生成一個calllist對象,它保存了調用BindImpl對象時所傳入的參數,然後在bindlist中調用注冊的函數。

  需要的注意的是,在bindlist調用函數時我們轉而調用了calllist的operator[]函數,通過它來判斷傳入的參數是占位符還是用戶傳入的參數,如果是占位符,那麼就返回calllist中保存的之前注冊的用戶傳入的信息。如果不是占位符,operator[]函數就單純的返回他接收的參數,也就是之前用戶調用BindImpl時傳入的參數。

  最後,我們通過一組重載的bind函數來實現對接收0個參數、1個參數、2個參數的支持,它們返回的是一個BindImpl對象。

 1 template<typename Func>
 2 BindImpl<Func, BindLinst0> bind(Func func)
 3 {
 4     return BindImpl<Func, BindLinst0>(func, BindLinst0());
 5 }
 6 
 7 template<typename Func, typename T1>
 8 BindImpl<Func, BindList1<T1> > bind(Func func, T1 data1)
 9 {
10     return BindImpl<Func, BindList1<T1> >(func, BindList1<T1>(data1));
11 }
12 
13 template<typename Func, typename T1, typename T2>
14 BindImpl<Func, BindList2<T1, T2> > bind(Func func, T1 data1, T2 data2)
15 {
16     return BindImpl<Func, BindList2<T1, T2> >(func, BindList2<T1, T2>(data1, data2));
17 }

  結果為:

30
Point::operator() called: a = 7

  得到的結果正如預期的一樣。

(完)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved