今天coding时发现这个知识点掌握得不牢固,故现写这篇博客记录一下自己看C++ Primer Plus学习Lambda表达式的笔记。
函数对象:C++中,把函数指针、函数符和Lambda函数统称为函数对象。
Lambda表达式:就地匿名/非匿名定义目标函数或函数对象,不需要额外写一个命名函数或函数对象。对于使用谓词的STL算法来说,Lambda表达式能在此处起大作用!(就地定义你想要的谓词,而不用通过翻阅上下文代码找到对应的函数对象,是不是稍微沉思一会儿你也觉得这种语法十分令人激动呢?please continue your reading)。
格式:
//匿名(不指定名字)的Lambda表达式(函数)格式
[capture](params){LambdaFuncBodyCode;};
//当你不指定Lambda函数的返回值类型时,编译器就会为你自动推断你的返回值类型
//若你return; or 根本无return语句,则默认返回值类型为void
[capture](params)->retVarType{LambdaFuncBodyCode;};
//指定Lambda函数的返回值类型为retVarType(使用C++11新增的后置返回值类型语法)
//指定名字的Lambda表达式(函数)格式
auto LambdaFuncName = [capture](params){LambdaFuncBodyCode;};
//这个Lambda函数名叫作LambdaFuncName(你当然可以用使用函数的方法调用Lambda表达式)
//当你不指定Lambda函数的返回值类型时,编译器就会为你自动推断你的返回值类型
//若你return; or 根本无return语句,则默认返回值类型为void
auto LambdaFuncName = [capture](params)->retVarType{LambdaFuncBodyCode;};
//这个Lambda函数名叫作LambdaFuncName(你当然可以用使用函数的方法调用Lambda表达式)
//指定Lambda函数的返回值类型为retVarType(使用C++11新增的后置返回值类型语法)
补充:
①若没有形参列表,可以直接将(params)省略不写。
[] {
if (1 == 1)return true;
return false;
});
//相当于 ==>
[](void)->bool {
if (1 == 1)return true;
return false;
});
②Lambda表达式可访问外部作用域内(这里的外部指的是Lambda函数表达式的外部)的任何动态变量,若要捕获要使用的变量,可将其名称放在中括号[中]。
解释:
[] - 不捕捉任何变量
[&] - 捕获外部作用域中所有变量,并作为引用在函数体内使用
(按引用捕获,此方式使得在Lambda表达式中对all变量的修改都将影响原始all变量的值)
[=] - 捕获外部作用域中所有变量,并作为副本在函数体内使用 (按值捕获)
(按引用捕获,此方式使得在Lambda表达式中对all变量的修改都将不会影响原始all变量的值)
(且拷贝的副本在匿名Lambda函数体内部是只读不可写的)
[=, &var] - 按值捕获外部作用域中所有变量(但在Lambda内部是只读不可写的),并按照引用捕获外部变量var
[var] - 按值捕获 var变量,同时不捕获其他变量
[&var] - 按引用捕获 var变量,同时不捕获其他变量
[this] - 捕获当前类中的 this 指针
(让lambda表达式拥有和当前类成员函数同样的访问权限)
(如果已经使用了 & 或者 =, 默认添加此选项)
demo_codes1:
//为了方便,这里直接在一个类中敲测试代码作演示:
class Person
{
private:
int m_Age;
public:
void showInfo(int x, int y)
{
auto x1 = [] {return m_Age; }; // error
auto x2 = [=] {return m_Age + x + y; }; // ok
auto x3 = [&] {return m_Age + x + y; }; // ok
auto x4 = [this] {return m_Age; }; // ok
auto x5 = [this] {return m_Age + x + y; }; // error
auto x6 = [this, x, y] {return m_Age + x + y; }; // ok
auto x7 = [this] {return m_Age++; }; // ok
}
};
x1:错误,没有捕获外部变量,so当然就不能使用类成员变量 m_Age
x2:正确,以值拷贝的方式捕获all外部变量
x3:正确,以引用的方式捕获all外部变量
x4:正确,捕获 this 指针,可访问类内部的成员
x5:错误,捕获 this 指针,虽可访问类内部的成员,但由于没有捕获到外部的变量x和y,因此不能访问他们
x6:正确,捕获 this 指针,x和y
x7:正确,捕获 this 指针,并且可以修改类对象内部变量的值
demo_codes2:
#include#include #include #include using namespace std; void mprint(int val) { cout << val << "t"; } bool f3(int x) { return x % 3 == 0; } bool f13(int x) { return x % 13 == 0; } class f_mod { private: int dv; public: f_mod(int d):dv(d){} bool operator()(int x) { return x % dv == 0; } }; int main(void) { srand((unsigned)time(NULL));//随机数种子 vector nums(10,0); for_each(nums.begin(), nums.end(),mprint); cout << endl; std::generate(nums.begin(), nums.end(), std::rand);//产生10个随机数并赋值给nums for_each(nums.begin(), nums.end(), mprint); cout << endl; //下面展示各种能做到输出被3和13整出数组元素个数的方法: //way1::使用函数符 auto cnt3 = count_if(nums.begin(), nums.end(), f3); auto cnt13 = count_if(nums.begin(), nums.end(), f13); cout << "Way 1nCount of numbers divisible by 3: " << cnt3 << endl; cout << "Count of numbers divisible by 13: " << cnt13 << endl; //way2:使用有名字的类对象(谓词) f_mod obj3(3); f_mod obj13(13); auto cn2t3 = count_if(nums.begin(), nums.end(), obj3); auto cn2t13 = count_if(nums.begin(), nums.end(), obj13); cout << "Way 2nCount of numbers divisible by 3: " << cn2t3 << endl; cout << "Count of numbers divisible by 13: " << cn2t13 << endl; //way3:使用匿名的类对象(谓词) auto cn3t3 = count_if(nums.begin(), nums.end(), f_mod(3)); auto cn3t13 = count_if(nums.begin(), nums.end(), f_mod(13)); cout << "Way 3nCount of numbers divisible by 3: " << cn3t3 << endl; cout << "Count of numbers divisible by 13: " << cn3t13 << endl; //way4:使用匿名Lambda表达式来deal(用后置语法来指定Lambda函数的返回值类型) auto cn4t3 = count_if(nums.begin(), nums.end(), [](int x)->bool {return x % 3 == 0; }); auto cn4t13 = count_if(nums.begin(), nums.end(), [](int x)->bool {return x % 13 == 0; }); cout << "Way 4nCount of numbers divisible by 3: " << cn4t3 << endl; cout << "Count of numbers divisible by 13: " << cn4t13 << endl; //way5:使用匿名Lambda表达式来deal(不指定Lambda函数的返回值类型) auto cn5t3 = count_if(nums.begin(), nums.end(), [](int x) {return x % 3 == 0; }); auto cn5t13 = count_if(nums.begin(), nums.end(), [](int x) {return x % 13 == 0; }); cout << "Way 5nCount of numbers divisible by 3: " << cn5t3 << endl; cout << "Count of numbers divisible by 13: " << cn5t13 << endl; //way6:像函数一样去使用有名Lambda表达式来deal auto mod3 = [](int x) {return x % 3 == 0; }; //名为mod3的Lambda表达式(函数) auto mod13 = [](int x) {return x % 13 == 0; };//名为mod13的Lambda表达式(函数) auto cn6t3 = count_if(nums.begin(), nums.end(), mod3); auto cn6t13 = count_if(nums.begin(), nums.end(), mod13); //auto res = mod13(14);你甚至可以把Lambda表达式就当作一个函数那样去使用! //cout << res << endl; cout << "Way 6nCount of numbers divisible by 3: " << cn6t3 << endl; cout << "Count of numbers divisible by 13: " << cn6t13 << endl; //way7:使用Lambda表达式的捕获capture[]中的[&var1,&var2,...]以引用的方式获取外部变量var1和var2 int coun7t3 = 0, coun7t13 = 0; auto cn7t3 = count_if(nums.begin(), nums.end(), [](int x)->bool {return x % 3 == 0; }); auto cn7t13 = count_if(nums.begin(), nums.end(), [](int x)->bool {return x % 13 == 0; }); for_each(nums.begin(), nums.end(), [&coun7t3, &coun7t13](int x) { coun7t3 += (x % 3 == 0); coun7t13 += (x % 13 == 0); }); cout << "Way 7nCount of numbers divisible by 3: " << coun7t3 << endl; cout << "Count of numbers divisible by 13: " << coun7t13 << endl; //way8:使用Lambda表达式的捕获capture[]中的[&]以引用的方式获取all外部变量 int coun8t3 = 0, coun8t13 = 0; for_each(nums.begin(), nums.end(), [&](int x) { coun8t3 += (x % 3 == 0); coun8t13 += (x % 13 == 0); }); cout << "Way 8nCount of numbers divisible by 3: " << coun8t3 << endl; cout << "Count of numbers divisible by 13: " << coun8t13 << endl; return 0; }
运行结果:



