这个函数调用应该不明确吗?
Should this function call be ambiguous?
前几天我偶然发现了这个,无法弄清楚哪个答案是正确的,或者两者都可以接受。
具体来说,我指的是 OtherFunction 中对 bar(T{}) 的调用。从我在编译器资源管理器上测试的内容来看,这个决定似乎是分裂的。MSVC和ICC一致认为这是模棱两可的,而GCC和Clang编译代码没有问题。
隐藏的命名空间内的函数栏通过依赖于参数的查找变得可见。此外,msvc/icc 将全局命名空间中的 bar 声明视为候选,而 gcc/clang 则不然。似乎不应该考虑全局命名空间中的声明,因为它是在调用 bar(T{}) 之后声明的,但我不确定我是否正确阅读了非限定名称查找的规则,或者标准在这方面是否模棱两可。
https://godbolt.org/z/HAS-Cv
编辑: 看起来只要使用/permissive- 选项,msvc 就已经解决了这个问题 (https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/)
template <typename T>
inline void OtherFunction () {
bar(T{});
}
namespace hidden {
struct Foo {};
inline void bar (Foo foo) {}
}
inline void bar (hidden::Foo foo) {}
void Function () {
OtherFunction<hidden::Foo>();
}
Gcc 和 Clang 是正确的。在定义OtherFunction
之后定义的全局bar
无法通过名称查找找到;而hidden::bar
可以通过ADL找到。
(强调我的)
对于模板定义中使用的依赖名称,查找将推迟到模板参数已知后,此时 ADL 检查从模板定义上下文以及模板实例化上下文中可见的函数声明
with external linkage (until C++11)
,而非 ADL 查找仅检查从模板定义上下文中可见的函数声明with external linkage (until C++11)
(换句话说,在模板定义之后添加新的函数声明不会使其可见,除非通过 ADL)。
代码有效,因此 msvc 和 icc 不正确。
由于bar
参数与类型相关,因此名称bar
是依赖名称,并且仅在实例化模板OtherFunction
时查找,而不是在定义模板时查找。
C++17 [临时候选人]/1:
对于后缀表达式是依赖名称的函数调用,可以使用通常的查找规则([basic.lookup.unqual]、[basic.lookup.argdep])找到候选函数,但以下情况除外:
对于使用非限定名称查找 ([basic.lookup.unqual]) 的查找部分,仅找到模板定义上下文中的函数声明。
对于使用关联命名空间 ([basic.lookup.argdep]) 的查找部分,仅找到来自模板定义上下文或模板实例化上下文的函数声明。
所以跳到[basic.lookup.argdep]/3:
设X是由非限定查找 ([basic.lookup.unqual]) 生成的查找集,设Y是由参数相关查找生成的查找集(定义如下)。如果X包含
- 集体成员的声明,或
- 不是using声明的块作用域函数声明,或
- 既不是函数也不是函数模板的声明
则Y为空。否则,Y是在与参数类型关联的命名空间中找到的声明集,如下所述。通过查找名称找到的声明集是X和Y的并集。
[目前的C++20草案重新安排了这些章节的措辞。特别是,有关在关联的命名空间中包括用于查找依赖名称的实例化上下文的规则现在列在 [basic.lookup.argdep]/4.5 中,并且只是 [temp.dep.candidate ] 中的一个注释。我不确定这样做的原因是否只是为了清楚起见,或者可能与模块的效果有关。
X是名称的非限定查找的结果,bar
仅考虑模板定义上下文中可见的声明。但是,由于模板定义上下文是翻译单元的开头,因此显然 X是空的。
由于X根本不包含任何内容,因此它不包含列出的项目,这会强制Y为空。因此,为了确定Y,我们查看与参数类型关联的命名空间。这个实例化的参数类型是hidden::Foo
,所以唯一关联的命名空间是hidden
,名称查找的单一结果是函数hidden::bar
。
::bar
在此名称查找中不可见,因此bar(T{})
表达式不能不明确。
- 父类的私有函数会导致对具有相同名称和相似参数的子类中的公共函数的不明确调用
- 对重载函数find_first_not_of的不明确调用
- 调用'Node'构造函数是不明确的
- "fpclassify":对重载函数的不明确调用
- 为什么调用具有通用或 r 值引用的重载覆盖函数是不明确的?
- 重载调用是不明确的:一对内联映射作为构造函数参数
- 如果存在具有不同参数的继承成员,为什么对 C++ 结构函数的调用不明确?
- C++具有可变参数包的函数的部分模板参数推导会在 Clang 和 MSVC 中产生不明确的调用
- 对静态重载(类)函数/方法的调用是不明确的
- 这个函数调用应该不明确吗?
- 使用列表初始化的不明确构造函数调用
- 循环依赖(类对类型定义,类型定义对类),前向声明给出不明确的调用
- 为什么初始值设定项列表中的元素数会导致不明确的调用错误
- C++中来自不同基类的不明确函数
- 对自身的不明确函数调用
- C++ 中的不明确函数
- 在c++中使用[]而不是函数调用
- 显然,不明确的调用不会在GCC上导致编译错误
- 可转换的类型和不明确的调用
- 为什么使用bind而不是函数调用?