gpt4 book ai didi

c++ - 为什么(不相关的)using 声明可以通过参数依赖查找调和重载歧义?

转载 作者:太空狗 更新时间:2023-10-29 21:12:36 26 4
gpt4 key购买 nike

这是问题 here 的跟进关于使用参数依赖查找 (ADL) 的函数重载。我想检查一下我在这种情况下对规则的理解,所以我写了一些测试代码。

首先,在 std 中当然没有 HasPtr 类的交换,所以我写了一个我自己的命名空间,除了已经在全局范围内定义的那个之外,它还包含一个 HasPtr 版本的交换。 using 声明按我的预期工作——产生了歧义错误,因为已经定义了交换的 HasPtr 版本,如“C++ 入门”,第 5 版中所做的那样。

然后我想看看如果我将 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);
}

奇怪的事情发生在第 27 行(using std::swap;)。如果我将其注释掉,名称 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 位。

最佳答案

这里的机制有三方面。

  1. using 声明,就像using std::swap一样,是一个声明。它将 swap 的声明引入函数的声明区域。

  2. 另一方面,using 指令不会将声明引入当前声明区域。它只允许非限定查找处理指定命名空间中的名称,就好像它们是在当前声明区域最近的封闭命名空间中声明的。

  3. 较小声明区域中的声明隐藏较大封闭声明区域中的声明。

关于上述内容,您的设置方式如下:

  1. std::swapswap(Foo, Foo) 中声明。
  2. myNS 中的名称可用于 swap(Foo, Foo),就好像它们是在同一个命名空间中用它声明的一样。
  3. #1 中添加的声明隐藏了#2 中可见的声明。
  4. ::swap 可以被 ADL 找到(尽管也被 #1 隐藏),但是 myNS::swap 不能。由于 myNS 版本是隐藏的,ADL 也找不到它,因此它不会与任何内容发生冲突。

当您删除 std::swap 的声明时,现在您可以看到 myNS::swap。 ADL 也会找到 ::swap,为您提供两个重载。它们都是有效的重载,并且会产生明显的歧义。

关于c++ - 为什么(不相关的)using 声明可以通过参数依赖查找调和重载歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46785093/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com