为什么 using 指令不影响 ADL?

Why doesn't a using directive affect ADL?

提问人:user3188445 提问时间:12/18/2014 更新时间:12/18/2014 访问量:533

问:

我试图理解为什么以下代码无法编译:

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=='
}

函数的第一行确实编译,这让我相信命名空间包含一个函数。但是,当我比较两个类型的值时,找不到此函数。相比之下,using 声明确实按预期工作,并允许 ADL 查找的第二行。fnsoperator==ns::Soperator==fns::operator==

我怀疑原因与以下事实有关:using 指令应该使符号看起来好像在全局命名空间中(因为这是命名空间和 )的共同祖先。但如果真的是这样,那为什么要找到这个函数呢?::alleqns::ns::operator==

更一般地说,我试图在库中提供一些有用(和相关)的重载,但不要强迫人们使用他们不想要的定义。我希望允许人们根据他们是否将专用的运算符命名空间导入自己的命名空间来启用或不启用 operator==(以及相关的其他运算符)在他们的类型上。现在看起来人们可能不得不编写大量使用声明(我可以用宏来简化,但很糟糕)。operator==

C++ 命名空间 argument-dependent-lookup

评论

2赞 Jonathan Wakely 12/18/2014
这听起来像是你在试图重新发明,这通常被视为一个失败的实验std::rel_ops
0赞 leemes 12/18/2014
@JonathanWakely 为什么失败了?你能给我一些解释这个问题的文章吗?
1赞 Jonathan Wakely 12/18/2014
@leemes stackoverflow.com/q/6225375/981959

答:

7赞 Jonathan Wakely 12/18/2014 #1

我怀疑原因与以下事实有关:using 指令应该使符号看起来好像在全局命名空间中(因为这是命名空间和 )的共同祖先。::alleqns

这是真的,但仅适用于非限定查找,而不是依赖于参数的查找:

7.3.4 [namespace.udir]:

  1. using 指令指定指定命名空间中的名称可以在 using 指令出现在 using 指令之后的作用域中使用。在非限定名称查找 (3.4.1) 期间,名称看起来就像在最近包含 using 指令和指定命名空间的封闭命名空间中声明一样。

由于这仅适用于非限定名称查找,因此,只有当名称查找“向外”查看封闭命名空间时,它才真正有用。它无助于从命名空间外部查找非限定名称(这是 ADL 所做的)。

下一段说:

  1. using 指令不会向显示它的声明性区域添加任何成员。

即 using 指令使名称在作用域中可见,但不向作用域添加新声明。

您看到的行为的原因很简单,因为标准说 ADL 忽略了使用指令:

3.4.2 [基本.lookup.argdep]

  1. 在考虑关联的命名空间时,查找与将关联的命名空间用作限定符 (3.4.3.2) 时执行的查找相同,但以下情况除外:
    — 将忽略关联命名空间中的任何 using 指令。