【问题标题】:The difference between declaring a name, introducing a name, and declaring an entity声明名称、引入名称和声明实体之间的区别
【发布时间】:2015-10-20 22:06:43
【问题描述】:

来自 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 出现的声明区域中声明。

在使用声明发生的声明区域中声明的名称是什么意思?

这是否意味着将该名称引入到使用声明发生的声明区域中?

声明名称和声明名称所表示的实体之间也有区别吗?

例子:

namespace N { static int i = 1; } /* Declares an entity denoted by 
    the name i in the declarative region of the namespace N. 
    Introduces the name into the declarative region of the namespace N.
    Declares the name i in the declarative region of the namespace N? */
using N::i; /* Declares the name i in the declarative region of the
    global namespace. Also introduces that name into the declarative
    region of the global namespace? Also declares the entity that the
    name i denotes? */ 

【问题讨论】:

  • 现在我正在回答你关于这个话题的第三个问题,我想我终于明白了!
  • @Barry 我正在耐心等待 Supremum 对标准的探索以触及第 14 条。啊,那将是一连串的问题和错误报告! :-)
  • @Supremum 我希望你没有以错误的方式接受上面的评论 - 这是友好的玩笑。你提出了有趣的问题,其中一些根本不明显。继续问!
  • 到目前为止:clang 中的 10 个未拒绝的错误(3 个已修复)和 gcc 中的 13 个未拒绝的错误(8 个已确认,0 个已修复)。到目前为止,我主要看的是第 3 章和第 7 章:P
  • 感谢巴里的帮助。我现在不那么困惑了。然而,我意识到 c++ 标准的术语不能 100% 精确,我不应该把所有的东西都看得太字面意思。理解使用的术语很好,但它们的精确度有限制。我可能应该更多地专注于制作我自己的 c++ 标准心智模型。这通常是我学习事物的方式,用我自己的话来解释。

标签: c++ entity declaration language-lawyer using-declaration


【解决方案1】:

根据第一原则,一个实体是,来自[基本]

值、对象、引用、函数、枚举器、类型、类成员、位域、模板、模板 专业化、命名空间、参数包或this。 [...] 每个表示实体的名称都由声明引入。

声明声明事物。被声明意味着它是由一个声明引入的,来自 [basic.scope.declarative]

每个名称都在程序文本的某个部分引入,称为声明区域,这是最大的部分 该名称在其中有效的程序的名称,即该名称可用作非限定名称的程序 指同一个实体。

声明所声明的名称被引入到声明发生的范围内,除了 friend 说明符 (11.3) 的存在,elaborated-type-specifier (7.1.6.3) 的某些用途,以及 using-directives (7.3.4) 改变了这种一般行为。

这些例外都与这里无关,因为我们谈论的是using-declarations而不是using-directives。让我稍微修改一下您的示例,以避免使用全局命名空间:

namespace N {        //  + declarative region #1
                     //  |
    static int i;    //  | introduces a name into this region
                     //  | this declaration introduces an entity
}                    //  +

首先,N::i 是在命名空间N 中声明并引入N 范围的实体。现在,让我们添加一个using-declaration

namespace B {        //  + declarative region #2
                     //  |
    using N::i;      //  | declaration introduces a name i
                     //  | but this is not an entity
}                    //  +

从 [namespace.udecl],我们有:

如果一个 using-declaration 命名一个构造函数(3.4.3.1),它在 使用声明出现的类(12.9);否则,在 using-declaration 中指定的名称是 同义词,表示另一个命名空间或类中的一组声明。

using-declaration using N::i 没有命名构造函数,因此名称 i 不是一个新实体,而是一个 同义词 N::i

所以基本上,is 都是在各自的命名空间中引入和声明的名称。在N 中,i 声明了一个具有静态链接的实体,但在B 中,i 声明了该实体的同义词——而不是新实体。

【讨论】:

  • 只是一个旁注:有没有不表示实体的名称?
  • @TemplateRex 是的。名称可以表示标签。
  • 啊,是的,有了goto,难怪我没有立刻想到它:)
【解决方案2】:

在声明区域中声明的名称是什么意思 using-declaration 出现在哪里?

我将尝试用一个我对它的理解的例子来回答这个问题(参考我在描述的代码中的 cmets):

// "namespace X {}" introduces a declarative region of the namespace X
namespace X {
  //The name SomeObject is now introduced into the declarative region X
  // It is only visible in that declarative region
  using Y::SomeObject;
}//Declarative region X ENDS here
// SomeObject NOT visible here

下面是一个示例,其中(编译器)错误清楚地表明了名称不可见的位置:

#include <iostream>

namespace A
{
  struct X{};
}

namespace B
{
  struct X{};
}

namespace C
{
  using A::X;

  void foo(X){}
}

namespace D
{
  using B::X;

  void foo(X){}
}

void foo(X){} //FAILS TO COMPILE - DELIBERATE!!!

int main() 
{
    return 0;
}

【讨论】:

    最近更新 更多