Consider the following snippet:
struct Base { };
struct Derived : Base { };
void f(Base &) { std::cout << "f(Base&)\n"; }
template <class T = int>
void g() {
Derived d;
f(T{} ? d : d); // 1
}
void f(Derived &) { std::cout << "f(Derived&)\n"; }
int main() {
g();
}
In this case, I reckon that the function call to f
at // 1
should be looked up in phase one, since its argument's type is unambigously Derived&
, and thus be resolved to f(Base&)
which is the only one in scope.
Clang 3.8.0 agrees with me, but GCC 6.1.0 doesn't, and defers the lookup of f
until phase two, where f(Derived&)
is picked up.
Which compiler is right ?
I think gcc (and visual studio, by the way) are right on this one.
In
T{} ? d : d
, there are 3 sub expressions:T{}
, obviously type dependentd
(2 times), not type dependentSince there is a type dependent sub expression and the ternary operator does not figure in the list of exceptions in §14.6.2.2, it is considered type dependent.
Using the latest version of the C++ standard Currently n4582.
In section 14.6 (p10) it says the name is bound at the point of declaration if the name is not dependent on a template parameter. If it depends on a template parameter this is defined in section 14.6.2.
Section 14.6.2.2 goes on to say an expression is type dependent if any subexpression is type dependent.
Now since the call to
f()
is dependent on its parameter. You look at the parameter type to see if it is depending on the type. The parameter isFalse<T>::value ? d : d
. Here the first conditional is depending on the typeT
.Therefore we conclude that the call is bound at the point of instantiation not declaration. And therefore should bind to:
void f(Derived &) { std::cout << "f(Derived&)\n"; }
Thus g++ has the more accurate implementation.
According to c++ draft (n4582) §14.7.1.5:
I would say gcc is more correct about this.
If you for example create an specialized version of
void g()
you get both compiler doing the same.