今天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表达式)
[&] - 捕获外部作用域中所有变量,并作为引用在函数体内使用
(按引用捕获,此方式使得在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<iostream>
#include<vector>
#include<algorithm>
#include<ctime>
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<int> 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 1\nCount 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 2\nCount 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 3\nCount 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 4\nCount 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 5\nCount 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 6\nCount 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 7\nCount 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 8\nCount of numbers divisible by 3: " << coun8t3 << endl;
cout << "Count of numbers divisible by 13: " << coun8t13 << endl;
return 0;
}
运行结果: