函数对象(function object)是指一个类重载函数运算符"()"后,使用类变量调用函数运算符时,其行为类似函数调用,所以也称为仿函数(functor)。
lambda表达式是函数对象的语法糖,使用三种括号来定义:
[](){};
[]内可以是空白,表示不捕获任何lambda表达式外部的任何变量,其内也可以声明需要捕获的lambda表达式外部的变量,可以是值捕获,也可以是引用捕获。
()内用于定义lambda表达式的参数;
{}内用于定义语句体,相当于函数的函数体。
lambda表达式直接调用的语法形式:
[](){}(); // 第二对小括号()表达式表示调用,内部的值对应第一对小括号()内声明的参数。
操作参数化是指用函数指针、函数对象或lambda表达式做函数参数。
lambda表达式这种语法形式的引入主要用于操作参数化。
1 成员函数与函数对象
成员函数:
include
class AddNum{
public:
AddNum(int num):num_(num){}
int addNum(int x)const{
return num_+x;
}
private:
int num_;
};
int main() {
auto add_num = AddNum(10);
auto x = add_num.addNum(5);
std::cout<<"x:"<<x<<std::endl;
return 0;
}
将成员函数改写为函数对象的形式:
include
class AddNum{
public:
AddNum(int num):num_(num){}
int operator()(int x)const{
return num_+x;
}
private:
int num_;
};
int main() {
auto add_num = AddNum(10);
auto x = add_num(5);
std::cout<<"x:"<<x<<std::endl;
return 0;
}
2 从函数对象到lambda表达式
lambda表达式:
include
int main() {
auto x = num=10{return num + x;}(5);
std::cout<<"x:"<<x<<std::endl;
return 0;
}
lambda表达式是函数对象的语法糖。
也可以对lambda表达式进行命名,命名后可以如同函数一样调用:
//代码效果参考:http://www.zidongmutanji.com/bxxx/162556.html
include
int main() {
auto add_num = num=10 {return num + x;};
auto x = add_num(5);
std::cout<<"x:"<<x<<std::endl;
return 0;
}
auto推导的lambda表达式类型相当于以下类型:
include
include
int main() {
std::function<int(int)> add_num = num=10 {return num + x;};
auto x = add_num(5);
std::cout<<"x:"<<x<<std::endl;
return 0;
}
3 操作参数化
操作参数化也就是用函数指针、函数对象或lambda表达式做函数参数。
如for_each()函数:
template
Function for_each(InputIterator first, InputIterator last, Function fn)
{
while(first!=last) {
fn (*first); // fn是for_each的参数,first也是,同时也是fn的参数
++first;
}
return fn; // or, since C++11: return move(fn);
}
3.1 使用函数指针让操作参数化
include
include
include
void print_int(int x){
std::cout<<"x: "<<x<<std::endl;
}
int main() {
std::vector<int> arr = {1,3,5,7,9};
std::for_each(arr.begin(),arr.end(),print_int);
return 0;
}
3.2 使用函数对象让操作参数化
include
include
include
struct print_int{
void operator()(int x){
std::cout<<"x: "<<x<<std::endl;
}
};
int main() {
std::vector<int> arr = {1,3,5,7,9};
std::for_each(arr.begin(),arr.end(),print_int());
return 0;
}
3.3 使用lambda表达式让操作参数化
include
include
include
int main() {
std::vector<int> arr = {1,3,5,7,9};
std::for_each(arr.begin(),arr.end(),[](int x){std::cout<<"x: "<<x<<std::endl;});
return 0;
}
4 lambda表达式还可以捕获表达式外部的变量
4.1 按值捕获
include
include
include
int main() {
int times = 2;
int others = 3;
std::vector<int> arr = {1,3,5,7,9};
std::for_each(arr.begin(),arr.end(),times{std::cout<<"x: "<<x*times<<std::endl;}); // 按值捕获times
return 0;
}
也可以全部按值捕获:
include
include
include
//代码效果参考:http://www.zidongmutanji.com/bxxx/484144.html
int main() {
int times = 2;
int others = 3;
std::vector<int> arr = {1,3,5,7,9};
std::for_each(arr.begin(),arr.end(),={std::cout<<"x: "<<x*times*others<<std::endl;}); // [=]表示全部按值捕获
return 0;
}
4.2 按引用捕获
include
include
include
int main() {
int times = 2;
int others = 3;
std::vector<int> arr = {1,3,5,7,9};
std::for_each(arr.begin(),arr.end(),×{std::cout<<"x: "<<x*++times<<std::endl;}); // [×]表示按引用捕获times
return 0;
}
也可以全部按引用捕获:
include
include
include
//代码效果参考:http://www.zidongmutanji.com/bxxx/472460.html
int main() {
int times = 2;
int others = 3;
std::vector<int> arr = {1,3,5,7,9};
std::for_each(arr.begin(),arr.end(),&{std::cout<<"x: "<<x*++times*++others<<std::endl;}); // [&]表示全部引用
return 0;
}