在默认情况下,为什么C ++ 11的lambda要求“可变”关键字来进行按值捕获?

简短示例:


#include <iostream>


int main()

{

    int n;

    [&](){n = 10;}();             // OK

    [=]() mutable {n = 20;}();    // OK

    // [=](){n = 10;}();          // Error: a by-value capture cannot be modified in a non-mutable lambda

    std::cout << n << "\n";       // "10"

}

问题:为什么我们需要mutable关键字?与传递给命名函数的传统参数完全不同。背后的原理是什么?


我给人的印象是,按值捕获的全部目的是允许用户更改临时值-否则,使用按引用捕获几乎总是更好,不是吗?


有什么启示吗?


(顺便说一句,我正在使用MSVC2010。AFAIK,这应该是标准的)


墨色风雨
浏览 511回答 3
3回答

MMMHUHU

您的代码几乎与此等效:#include <iostream>class unnamed1{&nbsp; &nbsp; int& n;public:&nbsp; &nbsp; unnamed1(int& N) : n(N) {}&nbsp; &nbsp; /* OK. Your this is const but you don't modify the "n" reference,&nbsp; &nbsp; but the value pointed by it. You wouldn't be able to modify a reference&nbsp; &nbsp; anyway even if your operator() was mutable. When you assign a reference&nbsp; &nbsp; it will always point to the same var.&nbsp; &nbsp; */&nbsp; &nbsp; void operator()() const {n = 10;}};class unnamed2{&nbsp; &nbsp; int n;public:&nbsp; &nbsp; unnamed2(int N) : n(N) {}&nbsp; &nbsp; /* OK. Your this pointer is not const (since your operator() is "mutable" instead of const).&nbsp; &nbsp; So you can modify the "n" member. */&nbsp; &nbsp; void operator()() {n = 20;}};class unnamed3{&nbsp; &nbsp; int n;public:&nbsp; &nbsp; unnamed3(int N) : n(N) {}&nbsp; &nbsp; /* BAD. Your this is const so you can't modify the "n" member. */&nbsp; &nbsp; void operator()() const {n = 10;}};int main(){&nbsp; &nbsp; int n;&nbsp; &nbsp; unnamed1 u1(n); u1();&nbsp; &nbsp; // OK&nbsp; &nbsp; unnamed2 u2(n); u2();&nbsp; &nbsp; // OK&nbsp; &nbsp; //unnamed3 u3(n); u3();&nbsp; // Error&nbsp; &nbsp; std::cout << n << "\n";&nbsp; // "10"}因此,您可以将lambda看作是使用operator()生成的类,除非您说它是可变的,否则该类默认为const。您也可以将[]内部捕获的所有变量(显式或隐式)视为该类的成员:[=]对象的副本或[&]对象的引用。当您声明lambda时就将它们初始化,就像有一个隐藏的构造函数一样。

守着星空守着你

我给人的印象是,按值捕获的全部目的是允许用户更改临时值-否则,使用按引用捕获几乎总是更好,不是吗?问题是,它“几乎”吗?常见的用例似乎是返回或传递lambda:void registerCallback(std::function<void()> f) { /* ... */ }void doSomething() {&nbsp; std::string name = receiveName();&nbsp; registerCallback([name]{ /* do something with name */ });}我认为这mutable不是“几乎”的情况。我认为“按值捕获”类似于“允许我在捕获的实体死亡后使用其值”,而不是“允许我更改其副本”。但这也许可以争论。
打开App,查看更多内容
随时随地看视频慕课网APP