c++ - type - lambda expression好處




為什麼C++ 11的lambda需要“可變”關鍵字來實現按值捕獲? (6)

簡短例子:

#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這應該是標準的)


我的印像是,按價值劃分的全部重點是允許用戶改變臨時的 - 否則我幾乎總是使用通過引用來捕獲更好,不是嗎?

n 不是一個臨時的。 n是您使用lambda表達式創建的lambda函數對象的成員。 默認的期望是調用你的lambda不會修改它的狀態,因此它是const的,以防止你意外地修改n


我的印像是,按價值劃分的全部重點是允許用戶改變臨時的 - 否則我幾乎總是使用通過引用來捕獲更好,不是嗎?

問題是,它“幾乎”? 經常使用的情況似乎是返回或傳遞lambda表達式:

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

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

我認為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聲明為有隱藏的構造函數時,它們被初始化。


它需要mutable因為默認情況下,函數對象每次調用時都會產生相同的結果。 這是面向對象的函數和使用全局變量的函數之間的區別。


現在有一個建議來減輕lambda聲明中mutable的需要: n3424


見5.1.2 [expr.prim.lambda]子條款5:

lambda表達式的閉包類型有一個公共的內聯函數調用操作符(13.5.4),其參數和返回類型分別由lambda表達式的parameter-declaration-clause和trailingreturn-type來描述。 當且僅當lambda表達式的參數聲明子句沒有跟隨可變時,此函數調用運算符被聲明為const(9.3.1)。

在litb的評論上編輯:也許他們想到了按值捕獲,這樣變量的外部更改不會反映在lambda內部? 參考文獻是雙向的,所以這是我的解釋。 不知道它是否有益。

在kizzx2的評論上編輯:使用lambda的最多次是作為算法的函子。 默認的const讓它可以在常量環境中使用,就像普通的const限定函數可以在那裡一樣,但是非常量限定的函數不能。 也許他們只是想讓這些案例更直觀,因為他們知道他們腦子裡發生了什麼。 :)





c++11