This is caused by two different CWG issues: CWG issue 2052 and CWG release 1391 .
First, CWG 1391. When x + a encountered, x + a regular name lookup finds among other overloads
template <typename T> double operator+ (T, double);
The output of the template argument is done by matching T with the type lhs + , which is double , so it outputs T as double . The second type of parameter does not contain a template parameter, so it is not considered in accordance with current rules. Of course, N::A cannot be converted to double , so the resulting specialization is not viable, but current rules say that the output of the template argument does not care about that; which will be processed when overload resolution is enabled.
The proposed resolution to WG 1391, among other things, adds a new standard to the standard:
If the output is successful for all parameters that contain template parameters that are involved in the output of the template argument, and all template arguments are explicitly specified, outputted, or derived from the template arguments by default, the remaining parameters are then compared with the corresponding arguments. For each remaining parameter P with a type that did not depend on the replacement of any explicitly specified template arguments, if the corresponding argument A cannot be implicitly converted to P , output is impossible. [Note: parameters with dependent types in which there are no template parameters to participate in the output of the template argument and parameters that become independent of the replacement of the explicitly specified template, the arguments will be checked during overload resolution. -end note]
In other words, if the argument ( a in our case) corresponding to the independent parameter ( double ) cannot be converted to the parameter type, the output will simply fail. Therefore, in our case, the output of the template argument post-CWG1391 will fail for this overload, and everything will be fine.
Clang implements the current rules, so the output is completed using T = double , a replacement occurs, and we encounter CWG 2052. We quote the entry by Richard Smith (Clang developer):
In type example
struct A { operator int(); }; template<typename T> T operator<<(T, int); void f(A a) { 1 << a; }
The output of the template argument is appropriate for the operator template, creating the signature operator<<(int,int) . The resulting declaration is synthesized and added to the overload set in 14.8.3 [temp.over], clause 1. However, this violates requirement 13.5 [over.oper], clause 6,
An operator function must be either a non-static member function or a non-member function that has at least one parameter whose type is a class, class reference, enumeration, or enumeration reference.
This is not the SFINAE context, so the program is poorly formed, rather than choosing the built-in operator.
In this case, there is no conversion, so the derived operator+(double, double) actually not viable, but non-viable candidates are not eliminated until you build a set of candidates, and at the same time creating a set of candidates causes a tough error.
The proposed resolution to CWG 2052 will make this SFINAE case instead - it also does the source work. The problem is that Clang also uses the current version of the standard.