C++11 function

来源:互联网 发布:红叶知弦调教片段 编辑:程序博客网 时间:2024/05/16 14:51

http://www.cnblogs.com/hujian/archive/2012/12/07/2807605.html


    function是一组函数对象包装类的模板,实现了一个泛型的回调机制。function与函数指针比较相似,优点在于它允许用户在目标的实现上拥有更大的弹性,即目标既可以是普通函数,也可以是函数对象和类的成员函数,而且可以给函数添加状态。
    声明一个function时,需要给出所包装的函数对象的返回值类型和各个参数的类型。比如,声明一个function,它返回一个bool类型并接受一个int类型和一个float类型的参数,可以像下面这样:
function<bool (int, float)> f;
    下面简要介绍一下function的比较重要的几个接口。
function();
    缺省构造函数,创建一个空的函数对象。如果一个空的function被调用,将会抛出一个类型为bad_function_call的异常。
    
template <typename F> function(F g);
    这个泛型的构造函数接受一个兼容的函数对象,即这样一个函数或函数对象,它的返回类型与被构造的function的返回类型或者一样,或者可以隐式转换,并且它的参数也要与被构造的function的参数类型或者一样,或者可以隐式转换。注意,也可以使用另外一个function实例来进行构造。这样做,并且function g为空,则被构造的function也为空。使用空的函数指针和空的成员函数指针也会产生空的function。如果这样做,并且function g为空,则被构造的function也为空。使用空的函数指针和空的成员函数指针也会产生空的function。
 
template <typename F> function(reference_wrapper<F> g);
    这个构造函数与前一个类似,但它接受的函数对象包装在一个reference_wrapper中,用以避免通过值来传递而产生函数或函数对象的一份拷贝。这同样要求函数对象兼容于function的签名。
 
function& operator=(const function& g);
    赋值操作符保存g中的函数或函数对象的一份拷贝;如果g为空,被赋值的函数也将为空。
 
template<typename F> function& operator=(F g);
    这个泛型赋值操作符接受一个兼容的函数指针或函数对象。注意,也可以用另一个 function 实例(带有不同但兼容的签名)来赋值。这同样意味着,如果g是另一个function实例且为空,则赋值后的函数也为空。赋值一个空的函数指针或空的成员函数指针也会使function为空。
 
bool empty() const;
    这个成员函数返回一个布尔值,表示该function是否含有一个函数或函数对象。如果有一个目标函数或函数对象可被调用,它返回 false 。因为一个function可以在一个布尔上下文中测试,或者与0进行比较,因此这个成员函数可能会在未来版本的库中被取消,你应该避免使用它。
 
void clear();
    这个成员函数清除 function, 即它不再关联到一个函数或函数对象。如果function已经是空的,这个调用没有影响。在调用后,function肯定为空。令一个function为空的首选方法是赋0给它;clear 可能在未来版本的库中被取消。
 
result_type operator()(Arg1 a1, Arg2 a2, ..., ArgN aN) const;
    调用操作符是调用function的方法。你不能调用一个空的 function ,那样会抛出一个bad_function_call的异常。调用操作符的执行会调用function中的函数或函数对象,并返回它的结果。
    下面分别给出使用function来包装普通函数,函数对象和类的成员函数的参考代码。
    1、普通函数
复制代码
1 int Add(int x, int y)2 3 {4             return x+y;5 }6 function<int (int,int)> f = Add;7 int z = f(2, 3);
复制代码

    2、函数对象

复制代码
 1 class CStudent 2 { 3 public: 4             void operator() (string strName, int nAge) 5             { 6                 cout << strName << " : " << nAge << endl;  7             } 8 }; 9 10 CStudent stu;11 function<void (string, int)> f = stu;12 f("Mike",  12);
复制代码

    3、类的成员函数

复制代码
 1 struct TAdd 2 { 3     int Add(int x,int y) 4     { 5         return x+y; 6     } 7 }; 8  9 function<int  (TAdd *, int, int)> f = TAdd::Add;10 TAdd tAdd;11 f(&tAdd, 2, 3);   // 如果前面的模板参数为传值或引用,直接传入tAdd即可
复制代码

     接下来我们来看看使用function来保存函数对象状态的情况。考虑下面的代码:

复制代码
 1 class CAdd 2 { 3 public: 4     CAdd():m_nSum(0) { NULL; } 5     int operator()(int i) 6     { 7           m_nSum += i; 8           return m_nSum; 9     }10 11     int Sum() const 12     {13         return m_nSum;14     }15 16 private:17     int m_nSum;18 };19 20 int main() 21 {22     CAdd add;23     function<int (int)> f1 = add;24     function<int (int)> f2 = add;25     cout << f1(10) << "," << f2(10) << "," << add.Sum() << endl;26     return 0;27 }
复制代码
     可能和大家想象的结果不一样,上面程序的输出是:10,10,0。我们将同一个函数对象赋值给了两个function,然后分别调用了这两个function,但函数对象中m_nSum的状态并没有被保持,问题出在哪儿呢?这是因为function的缺省行为是拷贝一份传递给它的函数对象,于是f1和f2中保存的都是add对象的拷贝,调用f1和f2后,add对象中的值并没有被修改。

    C++ 11中提供了ref和cref函数,来提供对象的引用和常引用的包装。要使function能够正确地保存函数对象的状态,我们可以这样来修改代码:

1 CAdd add;2 function<int(int)> f1 = ref(add);3 function<int(int)> f2 = ref(add);
     另外,在两个function之间赋值时,如果源function保存的是函数对象的拷贝,则目标function保存的也是函数对象的拷贝;如果源function保存的是函数对象的引用,则目标function保存的也是函数对象的引用。
标签: C++ 11
0 0
原创粉丝点击