Reputation: 313
I have been trying to compile a project (which is fine using gcc/g++) with clang and compilation stuck on a template invocation. I've tried to create the simplest similar piece of code exhibiting the same error message. Here it is:
#include <vector>
#include <utility>
#include <iostream>
using namespace std;
int A( double in )
{
return 1;
}
int A( int in )
{
return 1;
}
template<class M, class T>
M test(T input, M (fun) (T) )
{
return fun( input );
}
int main( int argc, const char *argv[] )
{
cout << test( (int) 1, A ) << test( (double) 1.2, A ) << endl;
return 0;
}
The error from clang (appears twice of course):
error: no matching function for call to 'test'
candidate template ignored: couldn't infer template argument 'M'
Gcc doesn't complain. Please note M is the return type and is always "int".
Does someone know which is right and why?
Thanks
Upvotes: 21
Views: 6846
Reputation: 14158
g++ is wrong. From C++11 [temp.deduct.type]p5:
The non-deduced contexts are: [...] - A function parameter for which argument deduction cannot be done because the associated function argument is [...] a set of overloaded functions, and [...] more than one function matches the function parameter type
This determination is made without regard to template parameters that might have been deduced elsewhere, so the fact that T
must deduce as int
is not relevant here. This makes the entire parameter M (fun)(T)
a non-deduced context. Therefore M
cannot be deduced, just as Clang claims.
g++ appears to incorrectly be using the 'T
= int
' deduction from the first function parameter when determining whether the second parameter is a non-deduced context. Reversing the order of the function parameters causes g++ to reject the code too:
int A(double);
int A(int);
template<class M, class T>
M test(M (fun) (T), T input) {
return fun( input );
}
int main( int argc, const char *argv[]) {
test(A, 1);
test(A, 1.2);
}
Upvotes: 8
Reputation: 33106
My previous answer (now deleted) was wrong. Clang is wrong.
The compiler should be able to deduce the type M
because the function argument is M(fun)(T)
. Note that there is no M
in the function pointer argument list, so this corresponds to the T()
(C++11) / T(*)()
(C++93) in 14.8.2.5:
where
(T)
represents a parameter-type-list where at least one parameter type contains aT
, and()
represents a parameter-type-list where no parameter type contains aT
.
Upvotes: 2