Lookup of dependent names in C++ template instantiation

こ雲淡風輕ζ 提交于 2019-12-03 04:50:57

tl;dr Foo<int> doesn't invoke any ADL, but Foo<X> would (where X is a class type).


First of all, in this code foobar is a dependent name because of (C++14/N3936) [temp.dep]/1

In an expression of the form:

postfix-expression ( expression-list opt )

where the postfix-expression is an unqualified-id, the unqualified-id denotes a dependent name if [...]

  • any of the expressions in the expression-list is a type-dependent expression (14.6.2.2), or

and t is a dependent name because it is part of a declaration T t where T is a template parameter and thus a dependent type.

Moving onto dependent name resolution, there is [temp.dep.res]/1 which introduces the fact that names can be both looked up in the definition context, and the instantiation context, and defines where the instantiation context is. I have omitted that for brevity, but in this example template class Foo<int>; is the point of instantiation.

The next bit is [temp.dep.candidate]/1:

For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1), only function declarations from the template definition context are found.
  • For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.

Those last two parts are the "two phases" of two-phase lookup. (Note - this section changed in wording from C++11 to C++14, but the effect in the same).

In the first phase, 3.4.1, no names are found for foobar.


So we move onto the second phase. The actual places that names are looked up as described in 3.4.2. The text is long but the here are two of the relevant rules:

  • If T is a fundamental type, its associated sets of namespaces and classes are both empty.

  • If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the innermost enclosing namespaces of its associated classes. [...]

So when you instantiate Foo<int>, then the second phase of lookup does not introduce any additional namespaces to search.

However, if you change your example to have struct X {}; and then change int to X everywhere, then the code does compile. This is because of the latter bullet point: ADL for an argument of class type does search the enclosing namespace of that class (which is the global namespace now), however ADL for an argument of built-in type does not search the global namespace.

Phase two lookup only includes name lookup rules that can't be applied in phase one- ADL, for example. Two-phase lookup is exactly that- some names are looked up in phase one, and some are looked up in phase two. This particular kind of name is a phase one name, as the compiler is perfectly capable of looking for foobar in the namespace(s) of the function during phase one.

Visual C++ does not implement two-phase name lookup.

Looks correct to me. While overload resolution is done only in phase 2, in phase 1 you already have to know that foobar(t) is a function call expression. If foobar names a type, t wouldn't even be a dependent name.

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