C++20标准中模板实例化第二阶段依赖名仅执行ADL查找的规则位置
C++20非限定依赖名查找规则的条款溯源问题
参考示例代码
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 }
规则梳理
前置判定
根据[temp.dep#2]的规定,示例中的非限定id foo属于依赖名,该名字的查找规则需遵循对应条款注释的明确说明:
[注:这类名字为未绑定名字,会在模板实例化点([temp.point])处,同时在模板定义上下文与实例化点上下文([temp.dep.candidate])中执行查找。——注完]
C++17的明确查找规则
C++17标准对依赖名的查找规则有完整明确的规定,对应条款为[temp.dep.res#1],解析依赖名时纳入考虑的名字来源包括:
- 模板定义点处可见的声明
- 来自函数参数类型关联命名空间的声明,覆盖实例化上下文([temp.point])与定义上下文
配套的[temp.dep.candidate#1]进一步明确了依赖名函数调用的查找边界:
对于后置表达式为依赖名的函数调用,候选函数使用常规查找规则([basic.lookup.unqual]、[basic.lookup.argdep])查找,但存在以下例外: - 非限定名查找部分仅可命中来自模板定义上下文的函数声明
- 关联命名空间查找([basic.lookup.argdep])部分仅可命中存在于模板定义上下文或模板实例化上下文的函数声明
按照上述规则可推知,模板实例化阶段的第二阶段查找,仅会执行ADL(依赖实参的查找)。
C++20的规则表述变化
C++20标准移除了原[temp.dep.res#1]独立条款,对[temp.dep.candidate#1]的表述做了调整,现行内容为:
对于后置表达式为依赖名的函数调用,候选函数使用来自模板定义上下文的常规查找规则([basic.lookup.unqual]、[basic.lookup.argdep])查找。[注:对于关联命名空间([basic.lookup.argdep])的查找部分,模板实例化上下文中定义的函数声明可被本次查找命中,如[basic.lookup.argdep]所述。——注完]若关联命名空间的查找未仅考虑模板定义与实例化上下文中的声明,而是覆盖所有翻译单元内这些命名空间下引入的全部外部链接函数声明,会发现调用为病态或可命中更优匹配,则程序行为未定义。
上述对ADL查找边界的约束内容,在当前C++20标准中仅以注释形式存在。
核心待解疑问
经梳理发现,当前C++20标准未清晰说明函数调用中非限定依赖名的查找执行规则,核心疑点包括:
- 哪条条款明确规定模板实例化阶段的第二阶段查找仅执行ADL?现有规则表述存在明确性不足的问题
- 若第二阶段查找执行常规非限定查找,示例中的#2代码会因
void foo(int)可在实例化上下文通过非限定查找命中而变为良构,与原有语义冲突 - 若上述规则对应条款未被遗漏,其在C++20标准中的准确位置在何处?
内容的提问来源于stack exchange,提问作者xmh0511
相关产品推荐
相关产品推荐

