这 4 个 lambda 表达式有什么区别?
What are the differences between these 4 lambda expressions?
我知道这对于 非菜鸟 C++
开发人员来说可能看起来很愚蠢,但这 4 个 lambda 表达式之间有什么区别?
Code:
#include <iostream>
#include <math.h>
#include <functional>
inline double MyFunction(double a, double b, double c) {
return (a + b + c);
}
inline void FunctionWrapper(std::function<double(double)> tempFunct, double value) {
std::function<double(double)> funct;
funct = tempFunct;
std::cout << "result: " << funct(value) << std::endl;
}
int main()
{
double value = 100.0;
FunctionWrapper([](double value) { return MyFunction(value, 1.0, 2.0); }, value);
FunctionWrapper([](double value) -> double { return MyFunction(value, 1.0, 2.0); }, value);
FunctionWrapper([value](double value) { return MyFunction(value, 1.0, 2.0); }, value);
FunctionWrapper([value](double value) -> double { return MyFunction(value, 1.0, 2.0); }, value);
}
好像也一样?使用两个不同的 "notations" 并使用值作为闭包?
第一个 lambda 是通常的。
第二个lambda表示它的return类型是double
.
最后两个 lambda 表达式不正确。 value
被值及其参数捕获,不应该尝试(有一个警告表明捕获不起作用)。它要么是参数,要么是捕获的变量(按值或引用)。
我想,它们应该是这样的:
[foo](double value) { return MyFunction(value, 1.0, foo); }, value);
在这种情况下,它们都产生相同的结果。但是,它们之间存在逻辑差异。
[](double value) { return MyFunction(value, 1.0, 2.0); }
这是一个 lambda,它采用 value
类型的单个参数并将其传递给 MyFunction
。它的 return 类型从 return
语句推导为 MyFunction
的类型,即 double.
[](double value) -> double { return MyFunction(value, 1.0, 2.0); }
这与之前的 lambda 相同,但这次它的 return 类型明确指定为 double
。在这种情况下是一样的,但如果 MyFunction
的 return 类型是其他东西,它将与第一个不同。在那种情况下,第一个会 return 什么 MyFunction
returns,而这个仍然 return double
.
[value](double value) { return MyFunction(value, 1.0, 2.0); }
这个取决于使用的标准版本。在 C++11 和 14 中,这个捕获 main
的局部变量 value
。但是,该捕获被 lambda 的参数 value
隐藏,因此它实际上是无用的。如果 lambda 被声明为例如,情况会有所不同。 [value](double v) { return MyFunction(value, 1.0, 2.0); }
。这会传递捕获的 value
,而不是它的参数。
在 C++17 及更高版本中,这已更改并且实际上格式错误(编译错误)。不再允许将 lambda 参数命名为与您捕获的参数相同的名称。
由于更改是缺陷报告 (CWG 2211),它具有追溯性,因此编译器拒绝此类代码是合法的,即使在早期的 C++ 版本中也是如此。
[value](double value) -> double { return MyFunction(value, 1.0, 2.0); }
与 lambda 数 3 相同,具有明确的 return 类型规范(3 和 4 之间的区别与 1 和 2 之间的区别完全相同)。
第二个 lambda 与第一个的不同之处在于您明确指定了 return 类型。由于第一个 lambda 的推导 return 类型相同,因此没有区别。
第三个和第四个 lambda 的格式不正确,因为它们声明了一个与捕获同名的参数。见标准规则:
[expr.prim.lambda.capture]
If an identifier in a simple-capture appears as the declarator-id of a parameter of the lambda-declarator's parameter-declaration-clause, the program is ill-formed.
[ Example:
void f() {
int x = 0;
auto g = [x](int x) { return 0; } // error: parameter and simple-capture have the same name
}
— end example
]
C++17采用了这种写法。
第一个和第二个 lambda 之间以及第三个和第四个之间的区别在于您是否明确指定 return 类型。在这里它产生相同的功能。
前两个 lambda 与第三个和第四个 lambda 之间的区别在于捕获。但是您的示例不适合说明捕获的效果。看下面的代码(live demo).
int main()
{
double v = 100.0;
auto lam1= [](double val) { return MyFunction(val, 1.0, 2.0); }; //A
auto lam2= [v](double val) { return MyFunction(v, 1.0, 2.0); }; //B
auto lam3= [&v](double val) { return MyFunction(v, 1.0, 2.0); }; //C
FunctionWrapper( lam1, v++ ); //1
FunctionWrapper( lam2, v++ ); //2
FunctionWrapper( lam3, v++ ); //3
std::cout << "v: " << v << '\n';
}
虽然 lam1
不捕获任何内容,但 lam2
按值捕获 v
,lam3
按引用捕获 v
。三个 FunctionWrapper
调用的输出分别为 103、103、106。这是因为尽管 v
在行 //1
中发生了变化,但在行 //2
中使用的是旧值。也就是说,按值捕获意味着值 v
在 lam2
行初始化时保持 //B
存储在 lam2
中。另一方面,在 //3
行中,使用了 v
的当前值。这是因为 lam3
持有对 v
.
的引用
我知道这对于 非菜鸟 C++
开发人员来说可能看起来很愚蠢,但这 4 个 lambda 表达式之间有什么区别?
Code:
#include <iostream>
#include <math.h>
#include <functional>
inline double MyFunction(double a, double b, double c) {
return (a + b + c);
}
inline void FunctionWrapper(std::function<double(double)> tempFunct, double value) {
std::function<double(double)> funct;
funct = tempFunct;
std::cout << "result: " << funct(value) << std::endl;
}
int main()
{
double value = 100.0;
FunctionWrapper([](double value) { return MyFunction(value, 1.0, 2.0); }, value);
FunctionWrapper([](double value) -> double { return MyFunction(value, 1.0, 2.0); }, value);
FunctionWrapper([value](double value) { return MyFunction(value, 1.0, 2.0); }, value);
FunctionWrapper([value](double value) -> double { return MyFunction(value, 1.0, 2.0); }, value);
}
好像也一样?使用两个不同的 "notations" 并使用值作为闭包?
第一个 lambda 是通常的。
第二个lambda表示它的return类型是double
.
最后两个 lambda 表达式不正确。 value
被值及其参数捕获,不应该尝试(有一个警告表明捕获不起作用)。它要么是参数,要么是捕获的变量(按值或引用)。
我想,它们应该是这样的:
[foo](double value) { return MyFunction(value, 1.0, foo); }, value);
在这种情况下,它们都产生相同的结果。但是,它们之间存在逻辑差异。
[](double value) { return MyFunction(value, 1.0, 2.0); }
这是一个 lambda,它采用
value
类型的单个参数并将其传递给MyFunction
。它的 return 类型从return
语句推导为MyFunction
的类型,即double.
[](double value) -> double { return MyFunction(value, 1.0, 2.0); }
这与之前的 lambda 相同,但这次它的 return 类型明确指定为
double
。在这种情况下是一样的,但如果MyFunction
的 return 类型是其他东西,它将与第一个不同。在那种情况下,第一个会 return 什么MyFunction
returns,而这个仍然 returndouble
.[value](double value) { return MyFunction(value, 1.0, 2.0); }
这个取决于使用的标准版本。在 C++11 和 14 中,这个捕获
main
的局部变量value
。但是,该捕获被 lambda 的参数value
隐藏,因此它实际上是无用的。如果 lambda 被声明为例如,情况会有所不同。[value](double v) { return MyFunction(value, 1.0, 2.0); }
。这会传递捕获的value
,而不是它的参数。在 C++17 及更高版本中,这已更改并且实际上格式错误(编译错误)。不再允许将 lambda 参数命名为与您捕获的参数相同的名称。
由于更改是缺陷报告 (CWG 2211),它具有追溯性,因此编译器拒绝此类代码是合法的,即使在早期的 C++ 版本中也是如此。
[value](double value) -> double { return MyFunction(value, 1.0, 2.0); }
与 lambda 数 3 相同,具有明确的 return 类型规范(3 和 4 之间的区别与 1 和 2 之间的区别完全相同)。
第二个 lambda 与第一个的不同之处在于您明确指定了 return 类型。由于第一个 lambda 的推导 return 类型相同,因此没有区别。
第三个和第四个 lambda 的格式不正确,因为它们声明了一个与捕获同名的参数。见标准规则:
[expr.prim.lambda.capture]
If an identifier in a simple-capture appears as the declarator-id of a parameter of the lambda-declarator's parameter-declaration-clause, the program is ill-formed. [ Example:
void f() { int x = 0; auto g = [x](int x) { return 0; } // error: parameter and simple-capture have the same name }
— end example ]
C++17采用了这种写法。
第一个和第二个 lambda 之间以及第三个和第四个之间的区别在于您是否明确指定 return 类型。在这里它产生相同的功能。
前两个 lambda 与第三个和第四个 lambda 之间的区别在于捕获。但是您的示例不适合说明捕获的效果。看下面的代码(live demo).
int main()
{
double v = 100.0;
auto lam1= [](double val) { return MyFunction(val, 1.0, 2.0); }; //A
auto lam2= [v](double val) { return MyFunction(v, 1.0, 2.0); }; //B
auto lam3= [&v](double val) { return MyFunction(v, 1.0, 2.0); }; //C
FunctionWrapper( lam1, v++ ); //1
FunctionWrapper( lam2, v++ ); //2
FunctionWrapper( lam3, v++ ); //3
std::cout << "v: " << v << '\n';
}
虽然 lam1
不捕获任何内容,但 lam2
按值捕获 v
,lam3
按引用捕获 v
。三个 FunctionWrapper
调用的输出分别为 103、103、106。这是因为尽管 v
在行 //1
中发生了变化,但在行 //2
中使用的是旧值。也就是说,按值捕获意味着值 v
在 lam2
行初始化时保持 //B
存储在 lam2
中。另一方面,在 //3
行中,使用了 v
的当前值。这是因为 lam3
持有对 v
.