[capture](parameters) mutable ->return-type{statement}
捕获列表与函数比必须存在 -> 可省略 如果无参数 参数列表连同括号可省略
#include "pch.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
void insert(vector<string>& word) {
word.push_back("the");
word.push_back("quick");
word.push_back("red");
word.push_back("fox");
word.push_back("jumps");
word.push_back("over");
word.push_back("the");
word.push_back("slow");
word.push_back("red");
word.push_back("turtle");
}
void print(vector<string> w) {
for (auto i : w)
cout << i << " ";
cout << endl;
}
void bigges(vector<string> word, vector<string>::size_type sz) {
cout << "原序列: " << endl;
print(word);
cout << "字典序升序:" << endl;
sort(word.begin(), word.end(),
[](const string& w1, const string& w2) { return w1 < w2; }
);
print(word);
cout << "去重: " << endl;
auto iter = unique(word.begin(), word.end());
word.erase(iter, word.end());
print(word);
cout << "原序列不变 按长度递增: " << endl;
stable_sort(word.begin(), word.end(),
[](const string& w1, const string& w2) { return w1.size() < w2.size(); }
);
print(word);
cout << "第一个大于等于" << sz << "的元素" << endl;
auto it = find_if(word.begin(),word.end(),
[sz](const string& w) {return w.size() >= sz; }
);
cout << "下标: " << it-word.begin() << endl;
cout << "值: " << *it << endl;
cout << "从it开始用->链接:" << endl;
for_each(it, word.end(), [](string w) {
cout << w << "->";
});
}
int main()
{
vector<string> word;
insert(word);
//完整的bigges
bigges(word, 4);
return 0;
}
创建lambda并返回对象时 要在结尾 } 后加分号
三种捕获方式:
值捕获
一定注意:是创建时候拷贝 而不是调用的时候拷贝
程序举栗☟☟☟
int main()
{
int x = 99;
auto f = [x](int y) {
cout << x + y << endl;
};
x++; //x = 100
f(1);
return 0;
}
下面改一下程序:
int main()
{
int x = 99;
x++; //x = 100
auto f = [x](int y) {
cout << x + y << endl;
};
f(1);
return 0;
}
可见 第一个程序中 x初始化是99 然后紧接着就创建了lambda 那么捕获到的x永远都是99 不论后面x值怎么变化,这就是所谓的创建时初始化
值捕获 在函数体中试图修改捕获变量是非法的
如果需求需要改变值捕获的局部变量值 在参数列表后加mutable关键字
int main()
{
int a = 1;
int b = 2;
int c = 3;
//隐式值捕获
auto f1 = [a]() mutable{
a++;
return a;
};
cout << f1() << endl;
cout << a << " " << b << " " << c << endl;
return 0;
}
但是这种方式只在内部改变 或者说改变捕获变量的副本
引用捕获
与值捕获相对应,在调用时初始化
int main()
{
int x = 99;
auto f1 = [&x]() {
x++;
return (x + 1);
};
x++; //x = 100
cout << f1() << endl;
cout << "x = " << x << endl;
return 0;
}
在lamdba中修改捕获的变量 相当于修改外部的变量 因为是引用绑定
注:必须保证引用的对象在lambda执行时是存在的。
IO流必须是引用捕获
隐式捕获
int main()
{
int a = 1;
int b = 2;
int c = 3;
//隐式值捕获
auto f1 = [=]() mutable{
a++;
b++;
c++;
return a + b + c;
};
cout << f1() << endl;
cout << a << " " << b << " " << c << endl;
return 0;
}
int main()
{
int a = 1;
int b = 2;
int c = 3;
//隐式值捕获
auto f1 = [=, &a]() mutable{
a++;
b++;
c++;
return a + b + c;
};
cout << f1() << endl;
cout << a << " " << b << " " << c << endl;
return 0;
}
隐式捕获就是捕获lmabda定义之前的所有变量
混合隐式捕获:
[&, identifie_list]
[= , identifie_list]
开头必须是值隐式或者引用隐式 如果开头是值隐式捕获,后面给出引用显式捕获列表 反之如此
注意 逗号后必须有个空格
附上C++14新规定:
Lambda函数
在C++11中,lambda函数参数需要被声明为具体的类型。C++14放宽了这一要求,允许lambda函数参数类型使用类型说明符auto。
auto lambda = [] (auto x, auto y) {return (x + y); }
尽管使用了C++11的关键字auto,泛型Lambda函数并不遵循auto类型推导的句法,而是遵循模板参数推导的规则(它们相似,但并不是在所有情况下都是相同的)。以上代码与下面的等价:
struct unnamed_lambda
{
template <typename T,typename U>
auto operator()(T x, U y) const
{
return (x+y);
}
};
auto lambda = unnamed_lambda();
Lambda函数
C++11的lambda函数通过值拷贝或引用捕获在外层作用域声明的变量。这意味着lambda的值成员不可以是只能move的类型。 C++14允许被捕获的成员用任意的表达式初始化。这既允许了通过move捕获,也允许了任意声明lambda的成员,而不需要外层作用域有一个具有相应名字的变量。
这是通过使用一个初始化表达式完成的:
auto lambda=[value{1}] { return value; }
lambda函数 lambda 会返回1,因为value被初始化为1。被声明的捕获变量的类型以与auto相同的方式,根据初始化表达式推断。
使用标准函数std::move可以使之被用以通过move捕获:
auto ptr=std::make_unique<int>(10);//See below for std::make_unique
auto lambda=[ptr{std::move(ptr)}] { return(*ptr); }
声明ptr{std::move(ptr)}使用了两次ptr。第一次使用声明了一个新的变量,但由C++的作用域规则,在初始化表达式求值完毕之前,该变量不在作用域内。所以第二个ptr表示之前在lambda之外声明的变量。
返回类型函数
C++11允许lambda函数根据return语句的表达式类型推断返回类型。C++14为所有的函数提供了这个能力。C++14还拓展了原有的规则,使得函数体并不是return expression;形式的函数也可以使用返回类型推导。
为了诱发返回类型推导,函数声明必须将auto作为返回类型,但没有C++11的后置返回类型说明符:
auto DeduceReturnType(); //Return type to be determined.
如果函数实现中含有多个return表达式,这些表达式必须可以推断为相同的类型。
使用返回类型推导的函数可以被前向声明,但在定义之前不可以使用。它们的定义在使用它们的翻译单元之中必须是可用的。
这样的函数中可以存在递归,但递归调用必须在函数定义中的至少一个return语句之后,例如:
auto Correct(int i)
{
if (i == 1)
return (i); // return type deduced as int
else
return (Correct(i-1)+i); // OK to call it now
}
但是下面这样写是错误的:
auto Wrong(int i)
{
if(i!=1)
return (Wrong(i - 1) + i); // Too soon to call this. No prior return statement.
else
return i; // return type deduced as int
}
对我画红的语句解释一下:
C++14 扩展了
1.如果函数体中有return之外的语句 也可以自动推导返回类型 可以不使用尾置返回类型
2.如果函数体有多个return 语句 则下一个必须与上一个返回类型相同
3.在捕获列表中可以临时自定义 变量名{变量值}