我想知道为什么以下代码 https://wandbox.org/permlink/lOVCxA1aY7HZejfV编译。
#include <iostream>
template<class T>
void print(T t) {
std::cout << t;
}
namespace ns {
struct A {};
}
std::ostream& operator<<(std::ostream& out, ns::A) {
return out << "hi!";
}
int main() {
print(ns::A{});
}
我的印象是,在实例化点,通过 ADL 查找不合格的依赖名称only- 不应考虑全局名称空间。我错了吗?
这是一个有趣的案例。您所描述的名称查找的工作原理总结如下:
[临时候选人](强调我的)
1 https://timsong-cpp.github.io/cppwp/n4659/temp.dep.candidate#1 For a 函数调用 where 后缀表达式是受抚养人
name,使用通常的查找规则找到候选函数
([basic.lookup.unqual], [basic.lookup.argdep]) 除了:
如果调用格式不正确或者会找到更好的匹配
关联命名空间内的查找考虑了所有函数
在这些命名空间中引入的具有外部链接的声明
所有翻译单元,不仅仅是考虑找到的那些声明
在模板定义和模板实例化上下文中,然后
该程序有未定义的行为。
我强调的一点是问题的关键。 “仅 ADL”的描述适用于 from 的函数调用foo(bar)
!它没有提到由重载运算符引起的调用。我们知道调用重载运算符相当于调用函数,但是该段落讨论的是特定形式的表达式,仅是函数调用的形式。
如果要将您的函数模板更改为
template<class T>
void print(T t) {
return operator<< (std::cout, t);
}
现在通过后缀表达式表示法调用一个函数,然后你瞧:GCC 发出与 Clang 等效的错误 https://wandbox.org/permlink/y7uqAfdl6Na91VTA。它可靠地实现了上面的段落,只是在涉及重载运算符调用时则不然。
那么这是一个错误吗?我想说是的。其目的肯定是像命名函数一样找到重载运算符(即使是从各自的表达式形式调用时)。所以GCC需要修复。但该标准也可以对措辞进行细微的澄清。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)