Max
Max

Reputation: 313

Clang " couldn't infer template argument " whereas gcc / g++ can. Which is right?

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

Answers (2)

Richard Smith
Richard Smith

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

David Hammen
David Hammen

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 a T, and () represents a parameter-type-list where no parameter type contains a T.

Upvotes: 2

Related Questions