为什么using指令不影响ADL?

use*_*445 5 c++ namespaces argument-dependent-lookup

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

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=='
}
Run Code Online (Sandbox Code Playgroud)

函数的第一行f确实可以编译,这使我相信命名空间ns包含一个function operator==。但是,当我比较type的两个值时ns::S,operator==找不到此函数。相比之下,using声明确实可以按预期工作,并且允许ADL f查找第二行ns::operator==。

我怀疑原因与使用指令应该使符号看起来像它出现在全局名称空间中有关::(因为这是名称空间alleq和的共同祖先ns)。但是,如果确实如此,那么为什么要::ns::operator==找到该功能呢?

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

Jon*_*ely 6

我怀疑原因与使用指令应该使符号看起来像它出现在全局名称空间中有关::(因为这是名称空间alleq和的共同祖先ns)。

这是正确的,但仅适用于不合格的查找,而不是依赖于参数的查找:

7.3.4 [namespace.udir]:

  1. 一个using指令规定,在被提名的命名空间中的名称可在范围内使用,其中using指令后出现using指令。在非限定名称查找(3.4.1)期间,这些名称看起来像是在包含使用指令和指定名称空间的最近的封闭名称空间中声明的一样。

由于这仅适用于不合格的名称查找,因此仅在从名称空间“向外”查找到包含名称空间的封闭名称空间中执行名称查找时,它才真正有用。它无助于从命名空间之外查找不合格的名称(这是ADL所做的)。

下一段指出:

  1. using伪指令不会将任何成员添加到它所在的声明性区域中。

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

您看到的行为的原因仅仅是该标准说ADL忽略了使用指令:

3.4.2 [basic.lookup.argdep]

  1. 在考虑关联的名称空间时,查找与将关联的名称空间用作限定符(3.4.3.2)时执行的查找相同,不同之处在于:
    —关联的名称空间中的所有using指令都将被忽略。