通过std::function引用使用lambda,不能修改lambda中的值

Zhe*_*eCi 6 c++ lambda c++11 c++14 c++17

lambda 通过std::function引用使用,但 lambda 中的值无法更改。我不知道为什么?我已经使用了参考资料,但仍然无法实现这一目标。

\n
#include <iostream>\n#include <functional>\n\nvoid myInvoke(const std::function<void()>& fn)\n{\n    fn();\n}\n\nint main()\n{\n    int i{ 0 };\n\n    // Increments and prints its local copy of @i.\n    auto count{ [i]() mutable {\n      std::cout << ++i << '\\n';\n    } };\n\n    myInvoke(count);\n    myInvoke(count);\n    myInvoke(count);\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

实际结果\xef\xbc\x9a

\n
1\n1\n1\n
Run Code Online (Sandbox Code Playgroud)\n

预期结果\xef\xbc\x9a

\n
1\n2\n3\n
Run Code Online (Sandbox Code Playgroud)\n

我去掉&符号后,运行结果并没有改变。我想这两者应该是有区别的,但是我不知道到底是什么!

\n

woh*_*tad 6

您尝试通过引用myInvoke接受该函数fn,但count您传递的 lambda 不是std::function.
每次使用myInvokelambda 调用时,都会std::function通过创建临时对象(副本)将其转换为 a 。这就是fn引用的内容。
因此将在副本i上进行修改并且不会影响您的lambda。 这也是为什么按值接受行为类似的原因。count
fn

处理它的一种方法是创建myInvoke一个函数模板,其中fn是模板参数(类型为T &),因此不需要进行转换。

代码示例:

#include <iostream>
#include <functional>

template <typename T>
void myInvoke(T & fn)
{
    fn();
}

int main()
{
    int i{ 0 };

    // Increments and prints its local copy of @i.
    auto count = [i]() mutable {
      std::cout << ++i << '\n';
    };

    myInvoke(count);
    myInvoke(count);
    myInvoke(count);
}
Run Code Online (Sandbox Code Playgroud)

输出:

1
2
3
Run Code Online (Sandbox Code Playgroud)

另一种方法是按照@Matt 在另一个答案中建议的方式制作count类型。 这也将防止每次调用创建临时副本,因为可以直接绑定到它。std::function<void()>
fn

注意:
提到的另一个选项是将 lambda 更改为i通过引用而不是通过值捕获:

//------------vv------------
auto count = [&i]() { ... };
Run Code Online (Sandbox Code Playgroud)

这将1 2 3按照您的预期输出,但这只是因为所有函数副本实际上都会修改i堆栈上的main
我认为这不是您想要的,而是仅增加ilambda 的成员。