c++11以前的函数对象
c++11以前的函数对象通常使用重载了()运算符的结构来实现。
例子中定义了一个拥有固定累加值成员的adder,通过构造一个对象,调用adder的operator()来实现函数调用。
struct adder {
adder(int n) : n_(n) {}
int operator()(int x) const
{
return x + n_;
}
private:
int n_;
};
int main()
{
auto sumer = adder(2);
cout<<sumer(1)<<endl;//输出3
return 0;
}
c++11的函数对象--lambda
lambda是c++11中出现的匿名函数对象,它以[]开始,以{}结束。
例子中是一个和上面功能一样的lambda表达式
auto adder = [](int x) {
return x + 2;
};
int main()
{
cout<<adder(1)<<endl;
return 0;
}
lambda表达式的存储:每一个 lambda 表达式都是一个单独的类型,所以只能使用 auto 或function<T>来接收结果。
():表示lambda表达式的函数入参,如果没有入参可以忽略
{}:表示lambda的函数体
->:返回值类型,如果返回值类型为void或者可以通过推到得到,可以省略
auto lamb = [a](int x)->int {
return x+a;
}
[]:表示lambda对变量的捕获方式,具体的捕获方式如下:
- []:默认不捕获任何变量;
- [=]:默认以值捕获所有变量(在非静态成员函数中,自动按引用捕获this);
- [&]:默认以引用捕获所有变量(在非静态成员函数中,自动按引用捕获this);
- [x]:仅以值捕获x,其它变量不捕获;
- [&x]:仅以引用捕获x,其它变量不捕获;
- [=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获;
- [&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获;
- [this]:通过引用捕获当前对象(针对在非静态成员函数中使用lambda);
- [*this]:通过传值方式捕获当前对象(c++17,针对在非静态成员函数中使用lambda);
- [x = 表达式]:按值捕获表达式(c++14)
- [&x = 表达式]:按引用捕获表达式(c++14)
捕获表达式中lambda对象func相当于保存了一个名叫tm的数据成员,在生成lambda表达式时进行初始化。
auto func = [tm = time()]() {
cout<<"current utc:"<<tm<<endl;
}
从工程的角度,大部分情况不推荐使用默认捕获符。更一般化的一条工程原则是:显式的代码比隐式的代码更容易维护。一般而言,按值捕获是比较安全的做法。按引用捕获时则需要更小心些,必须能够确保被捕获的变量和 lambda 表达式的生命期至少一样长,并在有下面需求之一时才使用:
- 需要在 lambda 表达式中修改这个变量并让外部观察到
- 需要看到这个变量在外部被修改的结果
- 这个变量的复制代价比较高
如果希望以移动的方式来捕获某个变量的话,则应考虑 变量名 = 表达式 的形式。表达式可以返回一个 prvalue 或 xvalue,比如可以是 std::move(需移动捕获的变量)。
mutable:标记捕获的内容可以被更改,默认情况下不可修改,因为lambda的()运算符重载函数默认是const的。
auto change = [age]() mutable {
++age;
}
泛型lambda表达式
相比于普通函数定义只有返回值可以以auto声明,lambda表达式可以对函数参数也使用auto声明。
auto lamb2 = [](auto x , auto y) {
return x + y;
}
补充资料
https://zh.wikipedia.org/zh-cn/ 函数对象