为什么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这应该是标准的)


它需要mutable因为默认情况下,函数对象每次调用时都会产生相同的结果。 这是面向对象的函数和使用全局变量的函数之间的区别。


你的代码几乎与此相同:

#include <iostream>

class unnamed1
{
    int& n;
public:
    unnamed1(int& N) : n(N) {}

    /* OK. Your this is const but you don't modify the "n" reference,
    but the value pointed by it. You wouldn't be able to modify a reference
    anyway even if your operator() was mutable. When you assign a reference
    it will always point to the same var.
    */
    void operator()() const {n = 10;}
};

class unnamed2
{
    int n;
public:
    unnamed2(int N) : n(N) {}

    /* OK. Your this pointer is not const (since your operator() is "mutable" instead of const).
    So you can modify the "n" member. */
    void operator()() {n = 20;}
};

class unnamed3
{
    int n;
public:
    unnamed3(int N) : n(N) {}

    /* BAD. Your this is const so you can't modify the "n" member. */
    void operator()() const {n = 10;}
};

int main()
{
    int n;
    unnamed1 u1(n); u1();    // OK
    unnamed2 u2(n); u2();    // OK
    //unnamed3 u3(n); u3();  // Error
    std::cout << n << "n";  // "10"
}

所以你可以把lambda当作用operator()生成一个类,除非你说它是可变的,否则默认为const。

您还可以将[](显式或隐式)内部捕获的所有变量视为该类的成员:[=]的对象副本或[&]的对象引用。 当你将lambda声明为有隐藏的构造函数时,它们被初始化。


我的印象是,按价值划分的全部重点是允许用户改变临时的 - 否则我几乎总是使用通过引用来捕获更好,不是吗?

问题是,它“几乎”? 经常使用的情况似乎是返回或传递lambda表达式:

void registerCallback(std::function<void()> f) { /* ... */ }

void doSomething() {
  std::string name = receiveName();
  registerCallback([name]{ /* do something with name */ });
}

我认为mutable不是“几乎”的情况。 我认为“按价值捕获”就像“让我在被捕获的实体死亡后使用它的价值”而不是“允许我改变它的副本”。 但也许这可以被争辩。

链接地址: http://www.djcxy.com/p/40325.html

上一篇: Why does C++11's lambda require "mutable" keyword for capture

下一篇: What optimization does move semantics provide if we already have RVO?