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 <typename T> double operator+ (T, double);
Template argument deduction is performed by match T
to the type of the lhs of +
, which is double
, so this deduces T
to be double
. 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 a double
, 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:
If deduction succeeds for all parameters that contain
template-parameters that participate in template argument deduction,
and all template arguments are explicitly specified, deduced, or
obtained from default template arguments, remaining parameters are
then compared with the corresponding arguments. For each remaining
parameter P
with a type that was non-dependent before substitution of
any explicitly-specified template arguments, if the corresponding
argument A cannot be implicitly converted to P
, deduction fails.
[Note: Parameters with dependent types in which no template-parameters
participate in template argument deduction, and parameters that became
non-dependent due to substitution of explicitly-specified template
arguments, will be checked during overload resolution. —end note]
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 an example like
struct A { operator int(); };
template<typename T> T operator<<(T, int);
void f(A a) { 1 << a; }
Template argument deduction succeeds for the operator template,
producing the signature operator<<(int,int)
. The resulting
declaration is synthesized and added to the overload set, per 14.8.3
[temp.over] paragraph 1. However, this violates the requirement of
13.5 [over.oper] paragraph 6,
An operator function shall either be a non-static member function or
be a non-member function that has at least one parameter whose type is
a class, a reference to a class, an enumeration, or a reference to an
enumeration.
This is not a SFINAE context, so the program is ill-formed, rather
than selecting the built-in operator.
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.