2014-09-06 68 views
1

我們有一個函數將一個函數對象作爲參數。函數有兩個重載,它們在函數簽名中有所不同。編譯器爲什麼不能推導出這個函數模板?

#include <functional> 

template <typename T> 
void foo(std::function<void(T)> bar) 
{ 

} 

template <typename T> 
void foo(std::function<void(int, T)> bar) 
{ 

} 

int main() 
{ 
    foo([](float number) { 

    }); 
    return 0; 
} 

但是,這段代碼不能編譯。

error C2784: 'void foo(std::function<void(int,T)>)' : could not deduce template argument for 'std::function<void(int,T)>' from 'main::<lambda_2b4e4413ec419a4ac179a0b64ebde221>' : see declaration of 'foo' 
error C2784: 'void foo(std::function<void(T)>)' : could not deduce template argument for 'std::function<void(T)>' from 'main::<lambda_2b4e4413ec419a4ac179a0b64ebde221>' : see declaration of 'foo' 

我認爲模板本身和過載都有問題。我如何提供兩個符合上述簽名的功能?

+0

拉姆達具體是不是自std ::功能 – 4pie0 2014-09-06 13:34:45

+1

模板類型推演試圖找到類型'T',這樣'的std ::功能<無效(INT ,T)>或'std :: function '分別與參數'[](float){}'的類型相等*。沒有這樣的'T'使得lambda的類型等於一些'std :: function <..>'類型。 – dyp 2014-09-06 13:36:32

回答

3

C++中的Lambdas是爲每個lambda對象專門創建的匿名類的實例,這意味着具有相同代碼的兩個lambda表達式實際上是不同的對象。

這也意味着你不能使用模板傳遞lambda,因爲沒有lambda類型。 Lambda既不是std::function(也不是從它派生的),也不是函數指針。它們是實現應用運營商的獨特類型,即operator()

可以使用的static_cast運營商做

template <typename T> 
void foo(std::function<void(T)> bar) 
{ 
} 

foo(static_cast< std::function<void(float)> >([](float number){})); 
//or 
foo(std::function<void(float)>{ [](float){} }); 
+1

'static_cast',順便說一句,甚至可以省略:'foo(std :: function {[](float){}});'但這並不回答OP的問題,我猜。 – dyp 2014-09-06 13:49:20

+0

好吧,一旦這是真的,最好用static_cast來表示強制轉換爲 – 4pie0 2014-09-06 17:32:23

1

的原因顯然是具有每個lambda表達式是有它自己類型的副作用之一。

這意味着例如您不能聲明lambda參數或指向lambda的指針。這也意味着,當需要類型推導時(例如模板實例化),您不能使用lambda表達式。

解決方案是儘快將lambda放入std::function<...>對象中,因爲這些對象具有可以在模板中指定和匹配的類型。

例如,你不能有一個函數返回一個lambda,或者將lambda存儲在一個成員中......但你可以返回一個std::function或將std::function存儲到成員中。

在你的代碼與

foo(std::function<void(float)>([](float number){}); 
+1

*「這也意味着當需要類型推斷時不能使用lambdas」*太籠統。你不能通過「模式匹配」等直接推導出lambda表達式的返回類型。你可以通過SFINAE來完成OP想要的內容。 *「例如,你不能有一個函數返回一個lambda」*我們現在有C++ 14,普通函數的返回類型推導。 *「或將lambda存儲在成員中。」*通過推導lambda的類型並使用類模板,總是可以做到這一點。你*不能*做的,(恕我直言更準確),是* name * lambda的類型直接。 – dyp 2014-09-06 20:58:46

相關問題