2013-02-14 72 views
1

我仍然在努力與一些C++語法。
這次我想添加lambda的額外參數。但是,爲了使代碼通用I螞蟻能夠接受任何函數及其參數:我想通過一個lambda作爲參數與模板可變參數

#include <functional> 
#include <exception> 

template<typename R> 
class Nisse 
{ 
    private: 
     Nisse(Nisse const&)    = delete; 
     Nisse(Nisse&&)     = delete; 
     Nisse& operator=(Nisse const&) = delete; 
     Nisse& operator=(Nisse&&)  = delete; 
    public: 
     //Nisse(std::function<R()> const& func) {} // disable for testing 

     template<typename... Args> 
     Nisse(std::function<R(Args...)> const& func, Args... a) {} 
}; 

int main() 
{ 
    // I was hoping this would deduce the template arguments. 
    Nisse<int> nisse([](int a,double d){return 5;},12,12.0); 
} 

這產生:

> g++ -std=c++0x Test.cpp 
Test.cpp:21:61: error: no matching function for call to ‘Nisse<int>::Nisse(main()::<lambda(int, double)>, int, double)’ 
Test.cpp:21:61: note: candidate is: 
Test.cpp:16:9: note: template<class ... Args> Nisse::Nisse(const std::function<R(Args ...)>&, Args ...) 

我試圖明確指定模板類型:

Nisse<int> nisse<int,double>([](int a,double d){return 5;},12,12.0); 

但是這個(對我來說令人驚訝)是一個語法錯誤:

> g++ -std=c++0x Test.cpp 
Test.cpp: In function ‘int main()’: 
Test.cpp:21:23: error: expected initializer before ‘<’ token 
Test.cpp:21:65: error: expected primary-expression before ‘,’ token 
Test.cpp:21:73: error: expected ‘;’ before ‘)’ token 
+1

如果您想從Args ... args參數中推導出Args ...包,那麼[This answer](http://stackoverflow.com/a/11774533/500104)可能會對您有所幫助。如果你期望那些從'std :: function'推導出來的,你[運氣不好](http://stackoverflow.com/a/14784584/500104)。另外,我通常建議只接受'F f,Args ... args'。 – Xeo 2013-02-14 17:58:59

+0

請注意,我更改了我的評論,您可能需要重新閱讀它。 – Xeo 2013-02-14 18:00:59

回答

4

您無法從lambda推斷std::function模板參數。接受任意的可調用的通常的方法是用通用的參考:

template<typename F, typename... Args, 
     typename = typename std::enable_if<std::is_convertible< 
     decltype(std::declval<F>()(std::declval<Args>()...)), R>::value>::type> 
    Nisse(F &&f, Args... a): Nisse(std::function<R()>(std::bind(f, a...))) {} 

最終(匿名,默認的)模板參數在這裏用於驗證所述第一模板參數是像功能,並返回型R.

的結果
std::enable_if<std::is_convertible< 
    decltype(std::declval<F>()(std::declval<Args>()...)), R>::value>::type 

正如下面的@Yakk評論所述上面的表達式檢查F是一個函數類型,其結果是R.如果它工作,那麼一切都很好。如果失敗,則會生成編譯時錯誤(注意:這使用SFINAE)。

對於方法,SFINAE插入到返回類型中,但對於構​​造函數,這不是一個選項;歷史上添加了一個額外的默認構造函數參數,但添加默認的模板參數更加優雅,因爲它根本不會更改構造函數簽名。 SFINAE通過匿名模板參數對可變參數模板參數特別有吸引力,因爲用戶無法(意外地)覆蓋默認值。

+1

我會使用'is_convertible'而不是'is_same'。另外,'std :: result_of'不是SFINAE安全的,如果你傳遞了一些不起作用的東西,將觸發一個硬錯誤。 – Xeo 2013-02-14 18:01:25

+0

@Xeo'decltype(std :: declval ()(std :: declval )()...))''而不是'std :: result_of <...> :: type'會修復嗎? (我假設'result_of'不是SFINAE安全的,因爲默認的'std :: result_of'是未定義的而不是空的?如果是這樣,奇怪的設計決定。) – Yakk 2013-02-14 19:07:17

+0

你能解釋第三個模板參數還是解釋鏈接。 – 2013-02-14 19:20:57

相關問題