2011-08-17 71 views
24

我做一個簡單的正常化向量(權重),試圖利用STL算法使代碼儘可能乾淨(我意識到這是相當瑣碎與循環):如何從C++ 11匿名函數中訪問局部變量?

float tot = std::accumulate(weights.begin(), weights.end(), 0.0); 
std::transform(weights.begin(), weights.end(), [](float x)->float{return(x/tot);}); 

目前,tot對於匿名函數是不可見的,所以這不會被編譯。使匿名函數可見的局部變量的最佳方式是什麼?

+0

對不起,0應該是0.0!編輯 – bd1

回答

39

您需要關閉。

float tot = std::accumulate(weights.begin(), weights.end(), 0); 
std::transform(weights.begin(), weights.end(), [tot](float x)->float{return(x/tot);}); 

在這種情況下,tot是通過值捕獲的。 C++ 11個lambda表達式支持捕獲由:

  1. [x]
  2. [&x]參考
  3. 通過參考當前在範圍內的任何變量[&]
  4. 相同3,但通過值[=]

你可以在逗號分隔的列表[x, &y]中混合上述任何一個。

+0

太棒了!在STL中有關於C++ 11匿名函數用法的很好的Web /書籍參考?我在網上發現的很多內容都是匿名函數的過時替代方法,或者是隨機發布的博客。 – bd1

+1

@ bd1 C++ 0x上的維基百科實際上相當不錯。此外,公衆可以使用的最後一個標準草案被稱爲n3424。不幸的是,目前還沒有關於C++ 0x的書籍。 – pmr

+0

如果你用'[=]'做了一個閉包,並且它將封裝範圍中的_all_變量複製,那麼它是否包含全局變量?它什麼時候停止上升範圍階梯? –

2

您需要添加tot的「捕獲列表」:

float tot = std::accumulate(weights.begin(), weights.end(), 0); 
std::transform(weights.begin(), weights.end(), [tot](float x)->float{return(x/tot);}); 

或者您可以使用捕捉默認捕捉tot含蓄:

float tot = std::accumulate(weights.begin(), weights.end(), 0); 
std::transform(weights.begin(), weights.end(), [=](float x)->float{return(x/tot);}); 
8

拉姆達可以「捕獲」變量從環境範圍:

[ ..., N, ... ](int a, int b) -> int { return (a + b) * N; } 
^^^^^^^^^^^^^ ^^^^^^^^^^^^  ^^^^ 
captured vars local params  ret.type 

您可以獲取或者你可以使用特殊的語法[=][&]來捕獲環境範圍內的任何東西,即任何你實際上最終使用的東西。

+0

如果我將lambda作爲函數參數解析,該怎麼辦?它會拋出一個錯誤,說lambda函數不是該參數的正確類型。 – Acidic

+0

@酸:因爲你不能說lambda表達式的*類型,所以很難有*函數*其參數是閉包類型。通常,如果需要管理不同類型的可調用集合,可以使用函數*模板*來推斷類型,或者使用類型擦除包裝器,例如'std :: function'。 –