【问题标题】:Can the same entity be declared in two different namespaces?可以在两个不同的命名空间中声明同一个实体吗?
【发布时间】:2026-02-22 04:20:07
【问题描述】:

我对 c++ 标准中的 §7.3.4/6 有疑问:

如果名称查找在两个不同的名称中找到名称声明 命名空间,并且声明不声明相同的实体并且做 不声明函数,名称的使用格式不正确。

似乎暗示在某些情况下,同一实体在两个不同的命名空间中声明。否则就不需要“并且声明不声明同一实体”这样的措辞。

有这种情况的例子吗?请记住,使用声明并不声明任何实体。它们只是指在其他地方完成的实体声明(可能间接通过其他使用声明)。然而,使用声明正在将它们的名称引入声明性区域,但这是另一回事。

还要记住 using-directives 也没有声明任何实体。

最后观察到,命名空间成员的异常定义(使用限定名称的定义)并未在它们出现的命名空间中声明任何内容,而只是在目标命名空间中声明。

【问题讨论】:

  • 我不确定这是否真的不适用于 using 声明。它说:“在两个不同的命名空间中找到一个声明 [...]”,而不是“在两个不同的命名空间中声明的实体”。
  • “记住 using-declarations 并没有声明任何实体。” 那为什么它们被称为 using-declarations?
  • 还有其他没有声明任何实体的声明,例如:static_assert 声明。术语声明在标准中以两种方式使用。
  • 对于它声明的成员名称?什么意思?
  • @Supremum:对于static_assert 来说,这有点小技巧,所以您可以将它们放在类定义中。不确定它是否重要。你能想到其他的例子吗?

标签: c++ namespaces declaration language-lawyer


【解决方案1】:

是的,extern。来自 [dcl.link]:

一个函数的两个声明 与具有相同函数名称(忽略限定它的命名空间名称)的 C 语言链接 出现在不同的命名空间作用域指的是同一个函数。 C 变量的两个声明 具有相同名称的语言链接(忽略限定它的命名空间名称)出现在不同的 命名空间范围引用同一个变量。

例如:

namespace A {
    extern "C" int x;
}

namespace B {
    extern "C" int x;
}

extern "C" {
    int x;
}

namespace D {
    using namespace A;
    using namespace B;
}

A::xB::x(和 ::x)都是同一个实体。因此,D::x 不是格式错误的。


进一步思考,结合using-declarations和using-directives,我们可以想出一个不依赖@的更简单的例子987654327@:

namespace A {
    int i;   
}

namespace B {
    using A::i;
}

namespace C {
    using A::i;
}

namespace D {
    using namespace B;
    using namespace C;
}

int main() {
    D::i = 4; // name lookup finds `i` declared in two different namespaces,
              // B and C. However, both of those declarations refer to the
              // same entity, A::i
}

【讨论】:

  • @LightnessRacesinOrbit 里面有一句关于变量的。我可以写一个不同的例子。
  • @Supremum 我添加了一个更简单的非extern 示例 - 这个可能更容易看到。
【解决方案2】:

但是使用声明确实声明了实体的名称。来自 C++11 标准,§7.3.3[namespace.udecl]/1:

using-declaration 将名称引入到 using-declaration 出现的声明区域中。

使用声明

using typenameoptnested-name-specifier unqualified-id ;
using :: unqualified- id ;

在 using-declaration 中指定的成员名称在 using-declaration 出现的声明区域中声明。

【讨论】:

  • @Supremum 这并不真正适用于这个问题。 using-declaration 声明了一个新名称,但这无法在两个不同的实体中真正找到相同的名称。如果您尝试使用 using-declaration 两次引入相同的名称,这是一个硬错误。只有 using-directive 才能做到这一点,这就是您引用的句子出现的部分。
  • 该死的,C++ 标准在声明方面确实搞砸了。在 §7.3.4/6 中,名称查找找到名称声明的名称空间是什么意思?在命名空间 N { static int i = 1; } 使用命名空间 N;使用 N::i; int main() { i = 2;在非限定名称查找期间,我在哪个命名空间中找到?
  • @Supremum 在::,因为 using-declaration。没有那个,在N 因为using-directive。没有这两者,就无处可去。
  • 所以命名空间 N { static int i = 1; } 命名空间 M { 结构 i {}; } 使用 N::i;使用 M::i int main() { sizeof(i); }
  • 我开始怀疑将名称引入声明性区域与在那里声明该名称相同,但声明实体与在声明性区域中声明名称不同。
【解决方案3】:
namespace A{
void fun(){}
}
namespace B{
void fun(){}
}
int main()
{
using namespace A;
using namespace B;
fun()//ambiguous call here because this entity is present in both the namespaces 

}

在上面的代码中调用 fun 是不明确的,因为查找将无法找到正确的 fun 调用。 第二个例子如下:

namespace N { namespace A {int i;} }

struct A {static int i;};

using namespace N;

int i = A::i; 

在后一种情况下,调用不明确,因为实体“A”存在于两个命名空间(N 和全局命名空间)中。 希望这会有所帮助

【讨论】:

  • 我认为您错过了问题的重点。 OP知道这两件事。由于命名了不同的实体而导致代码格式错误,并且实体是函数时。 OP 正在询问第三种隐含情况,其中两个声明确实命名了相同的非功能实体,以及这如何可能。
最近更新 更多