C++ lambda:如何"冻结"局部变量的值?

tol*_*ira 3 c++ lambda

在下面的代码中,类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)

Pet*_*ter 7

你有两个问题.

一个与这里的答案有关: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)


mel*_*ene 7

这是一种方式:

#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::functionA构造时创建单个,而是延迟函数的创建直到get_myFunction被调用.否则我们只会捕获b开头的(仍然未初始化的)值.

  • 我们明确地b按价值捕获.我们不能只[b]在捕获列表中说因为外部b不是真正的变量,它只是真正意义上的成员*this和任何使用.这就是为什么不起作用:它按值捕获(这只是一个指针).bthis->b[=]this

    [b = b]语法要求C++ 14.

    另一种选择是[*this]捕获整个对象的副本.这需要C++ 17.