我试图理解为什么以下代码无法编译:
namespace ns {
struct S {};
}
namespace alleq {
inline bool
operator==(const ns::S &, const ns::S &)
{
return true;
}
}
namespace ns {
using namespace alleq;
// using alleq::operator==; // Works if you uncomment this
}
ns::S a;
void
f()
{
::ns::operator==(a, a); // OK
a == a; // Error: no match for 'operator=='
}
函数f
的第一行确实编译,这使我相信命名空间ns
包含函数operator==
。但是,当我比较类型ns::S
的两个值时,找不到此operator==
函数。相比之下,使用声明确实按预期工作,并允许f
的第二行通过ADL查找ns::operator==
。
我怀疑原因与使用指令的事实有关,使得符号看起来好像它在全局命名空间::
中(因为这是常见的)名称空间alleq
和ns
)的祖先。但如果确实如此,那么为什么::ns::operator==
会找到函数?
更一般地说,我试图在库中提供一些有用的operator==
(和相关的)重载,但是如果他们不想要它们,则不强迫人们使用这些定义。我希望允许人们根据他们是否将专用运算符命名空间导入到他们自己的命名空间中来启用或不启用operator ==(以及相关的其他运算符)。现在看起来人们可能不得不编写一些使用声明的东西(我可以用宏来简化,但是很糟糕)。
答案 0 :(得分:3)
我怀疑原因与使用指令的事实有关,使得符号看起来好像它在全局命名空间
::
中(因为这是常见的)名称空间的祖先alleq
和ns
)。
这是真的,但仅限于不合格的查找,而不是依赖于参数的查找:
7.3.4 [namespace.udir]:
- using-directive 指定指定命名空间中的名称可用于 using-directive 出现在 using-directive之后的范围内。在非限定名称查找(3.4.1)期间,名称看起来好像是在最近的封闭命名空间中声明的,其中包含 using-directive 和指定的命名空间。
醇>
由于这仅适用于非限定名称查找,因此当从名称查找中查找" outwards"封闭名称空间。它没有帮助从命名空间外部找到不合格的名称(这是ADL所做的)。
下一段说明:
- using-directive不会将任何成员添加到它出现的声明区域。
醇>
即。 using指令使作用域中的名称可见,但不会向作用域添加新的声明。
您看到的行为的原因很简单,标准说ADL忽略使用指令:
3.4.2 [basic.lookup.argdep]
- 在考虑关联的命名空间时,查找与关联命名空间用作限定符(3.4.3.2)时执行的查找相同,除了:
醇>
- 忽略关联命名空间中的任何using-directive。