2014-03-01 132 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