当前标准中模板实例化的第二阶段名称查找的相关规则在哪里

where's the relevant rule for phase two name lookup of template instantiation in the current standard

template<typename T>
void fun(T t){
   foo(t);  //#1 foo is a dependent name
}
void foo(int){
}
int main(){
  fun(0);  // #2 ill-formed
}

由于 unqualified-id footemp.dep#2 的从属名称,因此,此名称的查找名称规则应遵循以下规则,该规则在 [的注释中提到temp.dep#2]

[ Note: Such names are unbound and are looked up at the point of the template instantiation ([temp.point]) in both the context of the template definition and the context of the point of instantiation ([temp.dep.candidate]). — end note ]

从属名的查找规则在c++17标准中写的很清楚,即:
temp.dep.res#1

In resolving dependent names, names from the following sources are considered:

  • Declarations that are visible at the point of definition of the template.
  • Declarations from namespaces associated with the types of the function arguments both from the instantiation context ([temp.point]) and from the definition context.

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 ([basic.lookup.unqual], [basic.lookup.argdep]) except that:

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

换句话说,这些规则意味着只有 ADL 用于执行第二阶段查找。

但是,我在当前标准(即c++20)中找不到相关规则。 [temp.dep.res#1] 已从当前标准中删除。 [temp.dep.candidate#1] 修改为:
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 from the template definition context ([basic.lookup.unqual], [basic.lookup.argdep]). [ Note: For the part of the lookup using associated namespaces ([basic.lookup.argdep]), function declarations found in the template instantiation context are found by this lookup, as described in [basic.lookup.argdep]. — end note ] If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.

在现行标准中只是一个注释。在我看来,目前的标准并没有清楚地描述查找规则如何在函数调用中对非限定依赖名称执行。在当前标准中,相关规则在哪里规定只有ADL会在第二阶段执行?目前还不清楚。如果通常的非限定查找规则将在第二阶段执行,#2 将是良构的,因为 void foo(int) 可以通过非限定查找在实例化上下文中找到。如果我遗漏了什么,相关规则在哪里?

In other words, these rules mean that only ADL is used to perform in phase two lookup.

这是从给定的规范引用中得出的错误结论。您似乎混淆了两个不同的概念。

第一个概念是通常所说的“两阶段查找”:当模板被解析时,依赖于模板参数的名称无法在解析时查找。它们只能在实例化时查找。查找有两个阶段:一个用于非依赖名称,一个用于依赖名称。

第二个概念只是名称查找,它有两个名称范围可供搜索:常规非限定查找(在 [basic.lookup.unqual] 中定义)和参数相关查找(在 [basic.lookup.argdep 中定义) ]).非限定查找在代码本身的范围内搜索,而 ADL 在函数参数的命名空间范围内搜索。

模板名称查找的两个阶段都使用这些范围的两者。需要明确的是,从属名称查找 进行不合格查找。这就是为什么您引用的要点之一说“对于使用不合格名称查找的查找部分......”。如果从属名称查找没有使用非限定名称查找规则,则不会提及它们。

现在,从属名称查找确实限制了将候选名称与常规规则进行比较的内容。但它并不限于只是 ADL;它执行两个查找范围。

正如您所指出的,这些限制曾经在 [temp.dep.candidate]/1 中指定。但是他们有点移动了。

对于不合格的查找部分,新的 [temp.dep.candidate]/1 涵盖了您引用的内容,因为它说“通常的查找规则 来自模板定义上下文 ”。这将非限定查找的上下文指定为仅模板的定义。

请注意,第二个要点还表示要查看该范围,因此它涵盖了其中的一部分。

第二个要点的其余部分由 [basic.lookup.argdep]/4.5 涵盖:

If the lookup is for a dependent name ([temp.dep], [temp.dep.candidate]), any declaration D in N is visible if D would be visible to qualified name lookup ([namespace.qual]) at any point in the instantiation context ([module.context]) of the lookup, unless D is declared in another translation unit, attached to the global module, and is either discarded ([module.global.frag]) or has internal linkage.

这扩展了查找以包括“实例化上下文”,它在很大程度上与 C++17 文本匹配(尽管有基于模块的修改)。