C从函数指针函数对象到Lambda表达式让代码更有弹性更通用
函数对象,由类实现,类有属性,实例化为对象后表现为对象的状态。类可以重载函数运算符"()",对象对此运算符的调用看起来就如果函数的调用一样,不同的是,这是一个对象,所以有其状态,这是其与普通函数的独到之处,有其独特的适用场景。
看下面的实例:#include #include #include using namespace std; bool larger_than_80(double x) { return x>80; } void func(list& v) { list::iterator p = find_if(v.begin(), v.end(), larger_than_80); if (p!=v.end()) { cout<<*p< lst (arr, arr + sizeof(arr) / sizeof(*arr) ); func(lst); getchar(); return 0; }
如果谓词函数想更改为bool larger_than_60(double x) { return x>60; }
显然这不是一种便捷的方法,把代码写死(硬编码,hard coded)是不好的,于是,函数指针和函数对象就可以登场了:#include #include #include using namespace std; bool larger_than_80(double x) { return x>80; } void func(list& v) { list::iterator p = find_if(v.begin(), v.end(), larger_than_80); if (p!=v.end()) { cout<<*p<& v) { class CLarger_than { int v; public: CLarger_than(int vv) : v(vv) { } // store the argument bool operator()(int x) const { return x>v; } // compare }; CLarger_than Larger_than(70); list::iterator p = find_if(v.begin(), v.end(), Larger_than); if (p!=v.end()) { cout<<*p< lst (arr, arr + sizeof(arr) / sizeof(*arr) ); func(lst); func2(lst); getchar(); return 0; }
显然,函数对象有更大的灵活性。
通常重载函数调用运算符的函数体都只有几行代码,可以inline,由此,相对于函数指针来说,效率更高。与此同时,函数对象可以嵌在函数内定义,而使用函数指针引用的函数无法嵌套,所以使用函数对象可以让代码更加紧凑。
函数对象带有状态。函数对象相对于普通函数是"智能函数",这就如同智能指针相较于传统指针。因为函数对象除了提供函数调用符方法,还可以拥有其他方法和数据成员。所以函数对象有状态。即使同一个类实例化的不同的函数对象其状态也不相同,这是普通函数所无法做到的。而且函数对象是可以在运行时创建。
每个函数对象有自己的类型:对于普通函数来说,只要签名一致,其类型就是相同的。但是这并不适用于函数对象,因为函数对象的类型是其类的类型。这样,函数对象有自己的类型,这意味着函数对象可以用于模板参数,这对泛型编程有很大提升。
函数对象一般快于普通函数,因为其可以inline实现。函数对象一般用于模板参数,模板一般会在编译时会做一些优化。
但函数对象这种代码的写法似乎有点冗余,于是Lambda表达式便登场了。
Lambda表达式是从类创建函数的精简方式。这里讲的类,它仅有的成员就是函数调用运算符。Lambda表达式取消了类声明,并且使用了精简的符号来表示函数调用运算符的逻辑。class LessThan { public: bool operator()(int a, int b) { return a& v) { list::iterator p = find_if(v.begin(), v.end(), [](double a){return a>60;}); if (p!=v.end()) { cout<<*p<(sum) / static_cast(num); } private: int num; int sum; }; int main() { vector v{ 1, 3, 5, 7 }; MeanValue mv = std::for_each(v.begin(), v.end(), MeanValue{}); cout << mv.value() << endl; // output: 2.5 return 0; }
使用引用捕捉的lambda表达式: int main() { int x = 10; auto add_x = [x](int a) { return a + x; }; // 复制捕捉x auto multiply_x = [&x](int a) { return a * x; }; // 引用捕捉x cout << add_x(10) << " " << multiply_x(10) << endl; // 输出:20 100 return 0; }
主要的语法形式:
[]:默认不捕获任何变量;
[=]:默认以值捕获所有变量;
[&]:默认以引用捕获所有变量;
[x]:仅以值捕获x,其它变量不捕获;
[&x]:仅以引用捕获x,其它变量不捕获;
[=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获;
[&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获;
[this]:通过引用捕获当前对象(其实是复制指针);
[*this]:通过传值方式捕获当前对象;
其参数还可以自动推断:auto add = [](auto x, auto y) { return x + y; }; int x = add(2, 3); // 5 double y = add(2.5, 3.5); // 6.0
ref:
https://www.cnblogs.com/AlainGao/p/10675201.html
-End-