使用指令与使用声明

Using directive vs using declaration

本文关键字:声明 指令      更新时间:2023-10-16

你能解释一下为什么这段代码有效并打印 16;

#include <iostream>
namespace X {
int  p = 5;
}
namespace Y {
int  p = 16;
using namespace X;
}
int main()
{
std::cout << Y::p;
}

以及为什么此代码会抛出多个声明的错误

#include <iostream>
namespace X {
int  p = 5;
}
namespace Y {
int  p = 16;
using X::p;
}
int main()
{
std::cout << Y::p;
}

我听说使用指令不仅仅是使用任何名称声明的过程,因为它似乎的工作方式不同

但我不明白为什么,你能给出一些详细的解释吗?

同样,这个可以很好地打印 16,如果我只用 X::p 的声明替换使用该指令,它将抛出相同的错误

#include <iostream>
namespace X {
int  p = 5;
}
int  p = 16;
using namespace X;
int main()
{
std::cout << ::p;
std::cout << "n";
return 0;
}

关键的区别在于,use 声明就是声明。而使用指令不是。我知道这听起来很愚蠢,但这就是差异的本质。前者实际上将声明添加到声明性区域,而后者仅使某些名称在声明性区域中可用。

使名称在特定范围内可用,而不是声明它,旨在成为一件更弱的事情。如果存在另一个具有相同名称的声明,则在限定查找期间不考虑前者,如 [basic.scope.hiding]/4 所示:

在查找由命名空间名称限定的名称期间, 否则由using-指令可见的声明可以被命名空间中具有相同名称的声明隐藏 包含using-指令

这几乎解释了你的第一个代码片段。由于 using 声明,该名称有一个声明,因此不考虑由 using 指令显示的名称。不管哪个先来,宣言总是更有力。

您的第二个代码片段有两个声明,用于Y中的p。当涉及到这些时,通常的声明规则适用。第二个必须声明相同的内容,否则程序格式不正确。仅此而已,真的。

最后,在第三个代码片段中,它与第一个代码片段中的代码片段更相似。[basic.lookup.qual]/4 是这样说的:

以一元作用域运算符::​([expr.prim]) 为前缀的名称为 在全局范围内查找,在使用它的翻译单元中查找。 该名称应在全局命名空间范围内声明,或者应为 其声明在全局范围内可见的名称,因为using-directive([namespace.qual]).使用​::允许全局 要引用的名称,即使其标识符已被隐藏。

因此,除了要查找的命名空间之外,其他所有内容都与您的第一个示例一样。你们都声明它,并通过 using 指令使其可用。我引用的第一段决定了必须选择哪一段。