2011-10-10 169 views
37
#include <vector> 
#include <algorithm> 

void foo(int) 
{ 
} 

int main() 
{ 
    std::vector<int> v({ 1,2,3 }); 

    std::for_each(v.begin(), v.end(), [](auto it) { foo(it+5); }); 
} 

在編譯時使用汽車,上面的例子開始這樣的錯誤輸出:在lambda函數

h4.cpp: In function 'int main()': 
h4.cpp:13:47: error: parameter declared 'auto' 
h4.cpp: In lambda function: 
h4.cpp:13:59: error: 'it' was not declared in this scope 

這是否意味着關鍵字auto不應在lambda表達式中使用?

這工作:

std::for_each(v.begin(), v.end(), [](int it) { foo(it+5); }); 

爲什麼用auto關鍵字的版本不工作?

+1

我認爲,即使是一個lambda,它仍然工作的功能,必須有一個簽名。使用auto時,讓編譯器決定類型,這樣你的lambda在編譯時纔會有真正的簽名。 – Geoffroy

+3

我們確實需要下一個標準中的多態lambda表達式(AKA隱式模板)。這個問題只是人們假設'auto'以這種方式工作的幾個例子之一。我認爲沒有理由不應該。 –

+0

deft_code,我與你同在。對於汽車來說這是一個合乎邏輯的用例。 – Robert

回答

63

auto關鍵字不能用作函數參數的類型。如果你不想在lambda函數中使用實際的類型,那麼你可以使用下面的代碼。

for_each(begin(v), end(v), [](decltype(*begin(v)) it){ 
     foo(it + 5);   
}); 
+37

我們將在[C++ 14](http://en.wikipedia.org/wiki/C%2B%2B14#Generic_lambdas)中的lambdas中獲得'auto'支持。 –

+0

注意'decltype'中'begin(v)'之前的星。你想要的值類型不是迭代器類型。 (當你失敗時的錯誤信息會很神祕)。 –

4

在編譯器甚至可以實例化std::for_each之前,需要知道lambda的類型。另一方面,即使在理論上可行,auto只能通過查看函子的調用方式實例化for_each之後才能推斷出來。

如果可能的話,忘了for_each,並使用範圍爲基礎的,其有很多簡單的循環:

for (int it : v) { 
    foo(it + 5); 
} 

這應該也與auto(和auto&const auto&)很好地應付。

for (auto it : v) { 
    foo(it + 5); 
} 
+0

是的,但只適用於for_each,而不適用於其他算法。例如你想在lambda排序。 – CashCow

20

Herb Sutter在採訪中對此進行了簡要討論。您的auto參數的需求其實沒有什麼,要求任何功能應該申報與auto,像這樣的不同:

auto add(auto a, auto b) -> decltype(a + b) { return a + b; } 

但是請注意,這是不是真的在所有的功能,而是它的一個模板功能,類似於:

template <typename S, typename T> 
auto add(S a, T b) -> decltype(a + b) { return a + b; } 

所以你基本上是要求一個工廠,通過改變它的參數將任何功能到模板。由於模板在C++類型系統中是一種非常不同的實體(想想模板的所有特殊規則,比如兩階段查找和演繹),這將是一個徹底的設計變革,帶來不可預見的後果,很快就會成爲標準。

+1

不,不要求或要求:)我只是想知道爲什麼它不起作用。 –

+5

好吧,它與「爲什麼不是所有函數模板」的原理基本相同 - 它只是不適合該語言的設計。 –