2014-10-31 25 views
8

我正打算寫C++中的記憶模式,結束了以下辦法LAMBDA捕捉價值強制所有範圍的對象爲const

std::function<int(int)> Memoize(std::function<int(int)> fn) 
    { 
     std::map<int, int> memo; 
     std::function<int(int)> helper = [=](int pos) 
     { 
      if (memo.count(pos) == 0) 
      { 
       memo[pos] = fn(pos); 
      } 
      return memo[pos]; 
     }; 
     return helper; 
    } 

奇怪的是,我的編譯器VS 2012,拒絕與以下編譯錯誤

1>Source1.cpp(24): error C2678: binary '[' : no operator found which takes a left-hand operand of type 'const std::map<_Kty,_Ty>' (or there is no acceptable conversion) 

在我看來,編譯器故意將值作爲一個const對象捕獲所有東西。我無法找到任何有關此行爲的記錄參考。

任何人都可以幫助我理解這裏可能發生的事情嗎?

+0

不應該是'memo.count(pos)'?就目前而言,對於0以外的任何值,我們總是計算並存儲該值,即使它已經存在。 – 2014-10-31 08:51:31

+0

@PhilWright:是的,沒錯。其實我試圖調試我的代碼,而發佈忘記改變它。感謝您強調它。 – Abhijit 2014-10-31 09:15:51

回答

14

Lambdas的行爲或多或少像功能對象;就像一個函數對象一樣,它們有一個函數調用操作符,即operator()。對於非mutable lambda表達式,該函數是const

[expr.prim.lambda]

5爲一個非通用λ-表達的閉合類型具有一個公共 內聯函數調用操作符[。 ..] 此函數調用運營商或運營商 模板聲明const(9.3.1),當且僅當 拉姆達表達式的參數聲明子句後面沒有 mutable

因爲通過拷貝的行爲就好像它們是拉姆達的成員變量捕獲實體:

15 [...]對於由複製捕獲的每個實體,無名非靜態數據成員被聲明在封閉類型中。

和非成員mutable不能一個const成員函數內被修改([class.this]/1 [dcl.type.cv]/4),如果要修改所捕獲的實體你將不得不申報mutable lambda。

既然這樣你的拉姆達看起來是這樣的:

class Helper 
{ 
public: 
    int operator()(int) const; 
private: 
    std::map<int, int> memo; 
    std::function<int(int)> fn; 
}; 

你可以認爲mutable拉姆達爲具有非constoperator(),在你的情況下,lambda可以被定義如下:

std::function<int(int)> helper = [=](int pos) mutable 
// etc 
+1

+1,與對象函數(函數)相關的lambdas的完美解釋。 – vsoftco 2014-10-31 05:02:34

6

爲了使lambda函數非const,您需要添加mutable關鍵字:

std::function<int(int)> Memoize(std::function<int(int)> fn) 
    { 
     std::map<int, int> memo; 
     std::function<int(int)> helper = [=](int pos) mutable // <== HERE!! 
     { 
      if (memo.count(0) == 0) 
      { 
       memo[pos] = fn(pos); 
      } 
      return memo[pos]; 
     }; 
     return helper; 
    }