忽略函数的默认模板参数

时间:2014-03-01 23:02:00

标签: c++ templates default-arguments

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。

1 个答案:

答案 0 :(得分:3)

  

尽管将R模板参数默认初始化为A,但我必须提供第三个参数才能进行编译。

实际上,这与它是默认参数这一事实无关。编译器也不能推导出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的概念应该可以缓解其中的一些问题。