ADL 名称查找问题,正在使用 std::swap; swap(a,b) 与函数重载或内部作用域函数隐藏外部作用域函数有关?

ADL name lookup problem, is using std::swap; swap(a,b) related to function overloading or inner scope function hide outer scope function?

我知道 ADL 是什么,我知道在 C++ 中,内部作用域函数隐藏外部作用域函数。也就是说,名称不会跨范围超载。所以函数重载需要在相同的范围内完成。

所以现在我的问题是,对于这个通用代码片段:

#include <iostream>
#include <string>
using std::cout;
using std::endl;

namespace Foo{
    class Bar{
        friend void swap(Bar& a, Bar& b);
    };
    void swap(Bar& a, Bar& b){
        cout << "I am here" << endl;
    }
}

int main(int argc, char *args[]){
    Foo::Bar a, b;
    using std::swap; //These 2 lines
    swap(a, b);      //output is "I am here", Foo::swap is called
}

连同 ADL,是:

  1. 自定义swapstd::swap都可见,认为是重载,然后选择最匹配的?

  2. 首先找到自定义 swap,然后名称查找停止(std::swap 已隐藏)?


如果 1. 为真,它是如何工作的?函数重载超过 2 个不同的范围?这与我开头写的矛盾。 using std::swapstd::swap 引入当前范围。自定义 swapFoo::swap 中。

顺便说一句,这个答案What is “Argument-Dependent Lookup” (aka ADL, or “Koenig Lookup”)?似乎表明它们是函数重载。

Further, if for some reason both A::swap(A::MyClass&, A::MyClass&) and std::swap(A::MyClass&, A::MyClass&) are defined, then the first example will call std::swap(A::MyClass&, A::MyClass&) but the second will not compile because swap(obj1, obj2) would be ambiguous.

如果是函数重载,为什么我的swap(Bar& a, Bar& b)没有有他描述的歧义问题?他错了吗?


如果2.为真,根据C++ Primer 5th 18.2.3:

std::cin >> s;

is equivalent to:

operator>>(std::cin, s);

In this example, when the compiler sees the “call” to operator>>, it looks for a matching function in the current scope, including the scopes enclosing the output statement. In addition, because the >> expression has parameters of class type, the compiler also looks in the namespace(s) in which the types of cin and s are defined. Thus, for this call, the compiler looks in the std namespace, which defines the istream and string types. When it searches std, the compiler finds the string output operator function.

因此名称查找顺序为:当前范围 --> 封闭范围 --> 参数名称空间范围.

那为什么 std::swap 不隐藏自定义 swapusing std::swapstd::swap 引入当前范围,它具有更高的查找优先级。


我的两个假设在某些部分似乎都无效,我感到很困惑。需要一些帮助。提前致谢。

1. 是真的。对于 ADL

These function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.

std::swap 是通过通常的非限定名称查找找到的,而 Foo::swap 是通过 ADL 找到的,它们都在重载集中。 Foo::swap 是一个非模板函数,优先于 std::swap,后者是 overload resolution.

中的模板

F1 is determined to be a better function than F2 if implicit conversions for all arguments of F1 are not worse than the implicit conversions for all arguments of F2, and

...

4) or, if not that, F1 is a non-template function while F2 is a template specialization

关于链接答案中的引述,

if for some reason both A::swap(A::MyClass&, A::MyClass&) and std::swap(A::MyClass&, A::MyClass&) are defined,

实际上没有std::swap(A::MyClass&, A::MyClass&),这只是一个假设,如果有一个非模板std::swap(A::MyClass&, A::MyClass&)那么调用就会有歧义 ...