不合格的名称查找
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。于是
有问题的<
被认为是开始一个模板参数列表,也就是说
f<N::A>
被解析为 template-id,这意味着
f<N::A>(N::A())
被解析为函数调用表达式,即
- 执行 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
- [...].
这来自标准 (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。于是
-
有问题的
<
被认为是开始一个模板参数列表,也就是说f<N::A>
被解析为 template-id,这意味着f<N::A>(N::A())
被解析为函数调用表达式,即- 执行 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
- [...].