Pergunta

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; } );

This gives the compiler error:

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; } );
                                                                            ^

Despite having the R template argument default initialised to A, I have to provide the third argument in order for this to compile. Is there something else I have to do in order to use default template arguments?

I'm using g++ v4.8.1.

Foi útil?

Solução

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

Actually, this has nothing to do with the fact that it's a default argument. The compiler can't deduce A and B either. Take a look at this simple example:

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

You'd think this would be super easy, and A should be deduced as void. But nope, it can't be done. When deducing template parameters, the compiler doesn't consider what constructors the parameter type would have for each possible combination of template parameters. It would be intractable to perform this sort of deduction in general.

For now, you'll just have to make addMultiplyOperation accept any type, and hope it's callable...

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

If necessary, there are ways to deduce the types of the arguments that the function object can accept, for example as described in this answer: Is it possible to figure out the parameter type and return type of a lambda?

This will lead to some nasty compilation errors if the object passed in is not actually callable, or takes the wrong number of arguments. For now I'm not sure whether there's a nice way to solve this. Concepts, coming in C++14, should alleviate some of these issues.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top