这是关于使用参数依赖查找 (ADL) 的函数重载的问题的后续行动。我想检查我在这些情况下对规则的理解,所以我写了一些测试代码。
首先,当然,std 中没有 HasPtr 类的交换,所以我编写了自己的命名空间,其中包含一个 HasPtr 版本的交换,除了已经在全局范围中定义的交换。using 声明按我的预期工作——产生了一个模棱两可的错误,因为已经定义了一个 HasPtr 版本的交换,如 "C++ Primer", 5ed 中所做的那样。
然后我想看看如果我将 using 声明更改为 using 指令会发生什么。这本书说编译器将保持沉默,直到函数被实际调用。我想验证一下,所以代码如下:
#include <string>
class HasPtr {
public:
friend void swap(HasPtr&, HasPtr&);
std::string *ps;
};
void swap(HasPtr &lhs, HasPtr &rhs) {
swap(lhs.ps, rhs.ps); // swap the pointers, not the string data
}
namespace myNS {
void swap(HasPtr &lhs, HasPtr &rhs) {
std::string s = "in my name space";
swap(lhs.ps, rhs.ps); // swap the pointers, not the string data
}
}
class Foo {
friend void swap(Foo &lhs, Foo &rhs);
HasPtr h;
};
void swap(Foo &lhs, Foo &rhs) {
using std::swap; //<- commenting this line will cause error
using namespace myNS;
swap(lhs.h, rhs.h);
}
int main() {
Foo f1, f2;
swap(f1, f2);
}
using std::swap;
第 27 行 ( )发生了奇怪的事情。如果我将其注释掉,与已在全局范围中定义的签名完全相同的名称 myNS::swap 将被提升到全局范围,从而导致重载歧义错误,正如我所料。
但是,如果我不注释第 27 行并编译,则不会报告歧义错误。并且程序执行最初在全局范围内定义的 ::swap,就好像 using 指令using namespace myNS;
没有解除 myNS::swap 一样,因此它不会添加到重载候选集中。我只是无法理解这种现象。为什么来自不相关命名空间的 using 声明(std 当然不包含交换的 HasPtr 版本)可以在 ADL 下协调重载歧义?为什么选择执行的是原来的 ::swap,而不是它在 myNS 中的竞争对手?第 27 行是否对重载过程有任何副作用(例如,从提升的命名空间中抑制名称,以便原始名称具有更高的优先级)?谢谢您的回答。
该问题可以在 Windows 7 上的 Visual Studio 2015 Update 3 和 ubuntu 14.04 上的 GCC 4.8.4(均为 64 位)中重现。