Conditional operator's return type and two-phase lookup

这一生的挚爱 提交于 2019-12-03 14:24:59

问题


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 ?


回答1:


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 is False<T>::value ? d : d. Here the first conditional is depending on the type T.

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.

14.6 Name resolution [temp.res]

Para 10:

If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation.

14.6.2.2 Type-dependent expressions [temp.dep.expr]

Except as described below, an expression is type-dependent if any subexpression is type-dependent.




回答2:


I think gcc (and visual studio, by the way) are right on this one.

n4582, §14.6.2.2

Except as described below, an expression is type-dependent if any subexpression is type-dependent.

In T{} ? d : d, there are 3 sub expressions:

  • T{}, obviously type dependent
  • d (2 times), not type dependent

Since 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.




回答3:


According to c++ draft (n4582) §14.7.1.5:

Unless a function template specialization has been explicitly instantiated or explicitly specialized, the function template specialization is implicitly instantiated when the specialization is referenced in a context that requires a function definition to exist. Unless a call is to a function template explicit specialization or to a member function of an explicitly specialized class template, a default argument for a function template or a member function of a class template is implicitly instantiated when the function is called in a context that requires the value of the default argument.

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.



来源:https://stackoverflow.com/questions/37563745/conditional-operators-return-type-and-two-phase-lookup

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!