在下面的代码中,类A有一个lambda作为数据成员,以及一个getter到这个lambda.是否有可能将lambda的局部变量"冻结"为getter返回lambda时的值?
换句话说,特别是在这个例子中,即使在myA.b的值改变之后,是否可以使代码打印6而不是150?
#include <iostream>
#include <functional>
class A
{
double b;
std::function<double(double)> myFunction = [=] (double x)
{
double localb = b;
return localb*x;
};
public:
void set_b(double value){b = value;};
std::function<double(double)> get_myFunction(){return myFunction;};
};
int main()
{
A myA;
myA.set_b(2.0);
std::function<double(double)> retrievedFunction = myA.get_myFunction();
myA.set_b(50.0);
std::cout << retrievedFunction(3.0) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
你有两个问题.
一个与这里的答案有关:C++ 11 lambdas:成员变量捕获陷阱,即lambda捕获成员变量via this
,这是唯一的方法.这意味着您将始终获得该成员的当前值b
.
即使您修复此问题,myFunction
也会在开头创建一次,这意味着它会在创建时捕获b的当前(未初始化!)值.
你需要的是在get_myFunction()
调用时准确生成lambda ,并让它捕获当前的值b
:
class A
{
double b;
public:
void set_b(double value){b = value;};
std::function<double(double)> get_myFunction() {
double localb = b;
return ([=] (double x) { return localb*x; });
}
};
Run Code Online (Sandbox Code Playgroud)
这是一种方式:
#include <iostream>
#include <functional>
class A
{
double b;
public:
void set_b(double value) { b = value; }
std::function<double(double)> get_myFunction() const {
return [b = b] (double x) { return b*x; };
}
};
int main()
{
A myA;
myA.set_b(2.0);
std::function<double(double)> retrievedFunction = myA.get_myFunction();
myA.set_b(50.0);
std::cout << retrievedFunction(3.0) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
关键点:
我们不是std::function
在A
构造时创建单个,而是延迟函数的创建直到get_myFunction
被调用.否则我们只会捕获b
开头的(仍然未初始化的)值.
我们明确地b
按价值捕获.我们不能只[b]
在捕获列表中说因为外部b
不是真正的变量,它只是真正意义上的成员*this
和任何使用.这就是为什么不起作用:它按值捕获(这只是一个指针).b
this->b
[=]
this
的[b = b]
语法要求C++ 14.
另一种选择是[*this]
捕获整个对象的副本.这需要C++ 17.