The following simplified example compiles in gcc
and Visual Studio
, but fails in clang
!?
namespace N
{
struct A {};
template <typename T>
double operator+ (T a, double d) {return d;}
template <typename T>
double operator+ (double d, T a) {return d;}
}
void test()
{
N::A a;
double x;
double y = a + x;
double z = x + a;
}
As I see it, the templated operator+
in namespace N
should be found by ADL.
Why does clang
disagree ? Is it a bug in clang
or in the other compilers ?
Here is the compilation error from clang 3.5.1 (tested on coliru), I don't understand what is the problem here...
10 : error: overloaded 'operator+' must have at least one parameter of class or enumeration type
double operator+ (double d, T a) {return d;}
^
18 : note: in instantiation of function template specialization 'N::operator+' requested here
double y = a + x;
^
7 : error: overloaded 'operator+' must have at least one parameter of class or enumeration type
double operator+ (T a, double d) {return d;}
^
19 : note: in instantiation of function template specialization 'N::operator+' requested here
double z = x + a;
^
2 errors generated.
Compilation failed
The example is simplified from real life code, of course. The intention is that any class defined inside namespace N has an overloaded operator+ with a double.
This is caused by two different CWG issues: CWG issue 2052 and CWG issue 1391.
First, CWG 1391. On encountering
x + a
, the usual name lookup finds, among other overloads,Template argument deduction is performed by match
T
to the type of the lhs of+
, which isdouble
, so this deducesT
to bedouble
. The second parameter's type contains no template parameter, so is not considered under current rules. To be sure,N::A
can't be converted to adouble
, so the resulting specialization is not viable, but the current rules say that template argument deduction doesn't care about this; that will be handled in overload resolution.The proposed resolution to CWG 1391, among other things, adds a new paragraph to the standard:
In other words, if an argument (
a
in our case) corresponding to a non-dependent parameter (double
) cannot be converted to the parameter's type, deduction would simply fail. So in our case, post-CWG1391 template argument deduction will fail for this overload, and everything would be well.Clang implements the current rules, however, so deduction succeeds with
T = double
, substitution occurs, and we encounter CWG 2052. Quoting the writeup from Richard Smith (a Clang dev):In this case, there's no conversion, so the deduced
operator+(double, double)
is actually not viable, but non-viable candidates are not eliminated until you have built the candidate set, and here building the candidate set is causing a hard error.The proposed resolution to CWG 2052 will make this case SFINAE instead - also making the original code work. The problem is - Clang is implementing the current version of the standard here, too.