2014-03-01 133 views
2
template < class A, class B, class R = A > 
void addMultiplyOperation(std::function< R (const A&, const B&) > func) 
{ 
    ... 
} 

addMultiplyOperation< float, int >([](float a, int b) { return a * b; }); 

這使編譯器錯誤:默認模板參數忽略

In function 'int main(int, char**)': 
error: no matching function for call to 'addMultiplyOperation(main(int, char**)::__lambda1)' 
addMultiplyOperation< float, int >([](float a, int b) { return a * b; }); 
                     ^
note: candidate is: 
note: template<class A, class B, class R> void addMultiplyOperation(std::function<R(const A&, const B&)>) 
void addMultiplyOperation(std::function< R (const A&, const B&) > func) 
    ^
note: template argument deduction/substitution failed: 
note: 'main(int, char**)::__lambda1' is not derived from 'std::function<R(const float&, const int&)>' 
addMultiplyOperation< float, int >([](float a, int b) { return a * b; }); 
                      ^

儘管具有R模板參數默認初始化爲A,我提供第三個參數,以便這編譯。爲了使用默認的模板參數,還有其他事情需要我去做嗎?

我使用的是g ++ v4.8.1。

回答

2

Despite having the R template argument default initialised to A , I have to provide the third argument in order for this to compile.

實際上,這與它是一個默認參數無關。編譯器無法推導出AB。看看這個簡單的例子:

template<class A> 
void f(function<void(A)> f) { } 
int main() { 
    auto lambda = [](){}; 
    f(lambda); 
} 

你會認爲這將是超級簡單,A應該推導出void。但是,不能這樣做。在推導模板參數時,編譯器不會考慮參數類型對於每個可能的模板參數組合都具有哪些構造函數。一般來說,執行這種演繹將是棘手的。

現在,你只需要做出addMultiplyOperation接受任何類型,並希望它的調用...

template<class Function> 
void addMultiplyOperation(Function func) { 
    // .... 
} 

如果需要的話,也有辦法來推斷參數類型的函數對象可以接受,例如在此答案中所述:Is it possible to figure out the parameter type and return type of a lambda?

如果傳入的對象不是實際可調用的,或者採用錯誤的參數數量,這會導致一些令人討厭的編譯錯誤。現在我不確定是否有很好的方法來解決這個問題。 C++ 14中的概念應該可以緩解其中的一些問題。

+1

+1我可以理解'A'沒有被推導出來,但是我告訴編譯器A是什麼,'R'和'A'是一樣的。但是,我再也不必實現這些語言邊緣案例,所以我不會抱怨... – cmannett85