【问题标题】:Local extern variable declaration with using-directive in the nearest enclosing scope在最近的封闭范围内使用 using 指令声明局部外部变量
【发布时间】:2015-10-08 05:34:11
【问题描述】:

这个程序是否符合 c++ 标准?

namespace X { int i = 1; }

using namespace X;

int main() {
    extern int i;
    i = 2;
}

我使用不同的编译器得到不同的结果:

  • GCC 和 Clang 给出链接器错误:未定义的 i 引用。

  • Visual c++ 接受程序。

【问题讨论】:

  • Clang 和 GCC 接受该程序。您使用的是哪个版本?
  • 这里可能的最新版本:melpon.org/wandbox
  • 我在示例中有一个错误。我现在已经修好了。现在 GCC 和 Clang 都给出了编译错误(对 i 的未定义引用)。
  • 我之前的评论中的意思是链接器错误而不是编译器错误。

标签: c++ namespaces language-lawyer using-directives


【解决方案1】:

[basic.link]/p6:

如果存在具有相同名称和类型的链接的实体的可见声明,忽略在最里面的封闭命名空间范围之外声明的实体,块范围声明会声明相同的实体并接收链接之前的声明。如果存在不止一个这样的匹配实体,则程序是非良构的。否则,如果没有找到匹配的实体,则块范围实体接收外部链接。

X::i 在 extern 声明的最内层封闭命名空间(即全局命名空间)之外声明,因此它被忽略。这意味着没有找到 i 的声明,因此 extern int i 是一个名为 i 的具有外部链接的新变量的声明。

您的程序将编译,但如果块范围 i 是 odr-used,则不会链接。

【讨论】:

  • [namespace.udir]p2 (eel.is/c++draft/namespace.udir#2) 在这里不适用吗?
  • @Supremum 这也是我关心的问题,但我认为来自 [basic.scope.pdecl]/p11 的注释,“块范围的函数声明和带有 extern 说明符的变量声明块范围指的是作为封闭命名空间成员的声明”,X::i 看起来好像它是在全局命名空间中声明的,但它不是成员,这使得它被排除在查找之外。不过,我在这方面有点摇摆不定,所以也许更有知识的人会提出一些明确的建议。
  • Hmm... 是的 X::i 显然不是全局命名空间的成员,因为它没有在那里声明,但根据 [namespace.udir]p2 名称查找应该像声明的那样表现在那里,因此是全局命名空间的成员。但是我认为应用 [basic.link]/p6 不是名称查找。因此我认为你是对的,我们应该在这里得到链接器错误。这是否意味着visual c++存在不报告链接器错误的bug?
  • @Supremum 是的,我认为 VC++ 有一个 bug。
  • @0x499602D2 我原以为将using namespace X; 更改为using X::i; 会编译。它也失败了,即使this answer 似乎表明 using 声明相当于该实体在同一区域中的声明。我不明白为什么它仍然失败,因为他们的声明显然是可见的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-13
  • 1970-01-01
  • 1970-01-01
  • 2017-12-02
  • 1970-01-01
  • 1970-01-01
  • 2013-11-01
相关资源
最近更新 更多