不合格的名称查找

Unqualified name lookup

这来自标准 (C++20) - 非限定名称查找 6.5.2。 谁能解释一下这里发生了什么?注意:这不是 ADL。我正在专门寻找对这个简短句子的解释:“在某些情况下,名称后跟 < 被视为 模板名称 ,即使名称查找没有找到模板名称"

int h;
void g();
namespace N{
  struct A{};
  template <class T> int f(T);
  template <class T> int g(T);
  template <class T> int h(T);
}
int x = f<N::A>(N::A()); // OK: lookup of f finds nothing; f treated as template name
int y = g<N::A>(N::A()); // OK: lookup of g finds a function, g treated as template name
int z = h<N::A>(N::A()); // error: h< does not begin a template-id

就是所谓的argument-dependent name lookup [6.5.2],使用unqualified name lookup时的特殊规则。

调用函数[或函数模板,规则相同]时,ADL 使编译器考虑其参数的命名空间。

对于函数 [template] f(),编译器发现您在命名空间 N 中提供了参数,因此它 [编译器] 也会考虑在该范围内进行名称查找。

与函数 [template] g() 几乎相同,除了 void g(); 声明在重载决议中被考虑,因为 ::g() [top-level 命名空间]没有任何参数,N::g()获胜。

h()不同。变量名不能重载。对于 top-level 命名空间 h 是一个变量,所以你不能将它用作函数或函数模板。

编译器在当前命名空间中开始查找。然后,如果需要,它会继续查看参数的名称空间以查找可能的函数重载。

在最后一种情况下 h 被发现为 int h,而不是函数。所以不需要寻找函数重载。然后编译器发现使用 h 作为模板函数不起作用(因为它是 int h; - 错误)。

f<N::A>(N::A()) 中,< 可以是 less-than 运算符或启动模板参数列表。为了消除歧义,编译器需要查看 f< 之前的名称)是否命名了一个模板。

请注意,此时无法执行ADL,因为当编译器看到<时,他们甚至不知道是否有参数。

C++20 指定如果通常的名称查找什么也找不到,f 将被视为 template-name。于是

    有问题的
  1. <被认为是开始一个模板参数列表,也就是说
  2. f<N::A> 被解析为 template-id,这意味着
  3. f<N::A>(N::A())被解析为函数调用表达式,即
  4. 执行 ADL 以查看 f 的真实情况。

在 C++20 之前,当且仅当通常的名称查找找到模板时,< 之前的名称被视为 template-name,因此其中 none 发生,< 被视为运算符,f<N::A>(N::A()) 被视为错误。

更改由 P0846R0 完成。

C++20 [temp.name]/2:

An identifier is a template-name if it is associated by name lookup with a template or an overload set that contains a function template, or the identifier is followed by <, the template-id would form an unqualified-id, and name lookup either finds one or more functions or finds nothing.

C++20 [temp.names]/3:

When a name is considered to be a template-name, and it is followed by a <, the < is always taken as the delimiter of a template-argument-list and never as the less-than operator.

最新草案可以说更清楚 ([temp.names]/3):

A < is interpreted as the delimiter of a template-argument-list if it follows a name that is not a conversion-function-id and

  • [...]
  • that is an unqualified name for which name lookup either finds one or more functions or finds nothing, or
  • [...].