【问题标题】:What name spaces are there and what are the rules?有哪些命名空间以及规则是什么?
【发布时间】:2020-03-17 12:05:46
【问题描述】:

注意:这个问题是关于name space,而不是namespace

C++ 标准有一些对name space 的引用,但我没有看到它的定义。标准规定标签和宏位于不同的名称空间中。所有其他对 name space 的引用都在 C/C++ 兼容性部分,如下所示 (current draft):

这是 C 和 C++ 之间为数不多的不兼容之一,可归因于 新的 C++ 名称空间定义,其中名称可以在单个名称中声明为类型和非类型范围导致非类型名称隐藏类型名称,并要求使用关键字 class、struct、union 或 enum 来引用类型名称。 这个新的命名空间定义为 C++ 程序员提供了重要的符号便利,并有助于使用户定义类型的使用尽可能类似于基本类型的使用。

这个新的命名空间定义是什么?我在哪里可以找到它的标准?具体规则是什么?规则似乎比“非类型隐藏类型”更复杂。就像,这不会编译:

typedef int Foo; // Foo is a type
void Foo();      // not a type, but compile error, instead of hiding

但这确实:

struct Foo { }; // Foo is a type as well
void Foo();     // This hides the type Foo. "struct Foo" refers to the type

这也不编译:

struct Foo { };   // Type
namespace Foo { } // Non-type, but compiler error instead of hiding

【问题讨论】:

  • 实际的观点是命名空间是一个具有所有公共成员(子类)的单例类。请不要私刑我:-)
  • @peterh-ReinstateMonica 再次阅读问题
  • FWIW,您的链接链接到相关部分:受影响的子条款:[class.name] [另请参阅 [dcl.typedef]] 您可以查看这些部分以了解规则有效。
  • 至少有两个命名空间:一个用于标签[stmt.label]/1,一个用于宏[cpp]/8
  • 这有点有趣(对我来说),描述和示例都显示了与基本原理所提到的相反的内容;隐藏非类型名称的类型名称。鉴于草稿状态,我希望该段落会发生变化。

标签: c++ namespaces


【解决方案1】:

命名空间术语在 ISO C 标准中可能更为完善;引用ISO C11:

6.2.3 标识符的命名空间

如果一个特定标识符的多个声明在翻译单元中的任何位置可见,则句法上下文消除了引用不同实体的用法的歧义。因此,不同类别的标识符有单独的名称空间,如下所示:

  • 标签名称(通过标签声明和使用的语法消除歧义);
  • 关键字struct、union或enum的结构、联合和枚举(通过any32消除歧义)的标签;
  • 结构或工会的成员;每个结构或联合对其成员都有一个单独的名称空间(通过用于通过 . 或 -> 运算符访问成员的表达式的类型来消除歧义);
  • 所有其他标识符,称为普通标识符(在普通声明符中声明或作为枚举常量声明)。

C++ 的命名空间定义无论如何都不是最近的,并且在 [diff .class]/1 以其当前形式 ever since the ISO C++ Standard's introduction in '98。根据 OP 引用的 [diff.class]/1,它仅在与 ISO C 不同的上下文中以任何长度被提及。

Afaics 我们需要求助于 ISO C11/6.2.3 并将其与 ISO C++ 标准的 [diff.class]/1 结合起来,以便对 C++ 的(新)名称空间定义进行连贯而完整的描述,更少我们对 ISO C++ 标准的抨击,例如[basic.scope.hiding][class.name]/2[stmt.label]/1[cpp.replace]/8 等等,看看它的应用方式和位置。

[class.name]/2

类声明将类名引入声明它的作用域,并将该名称的任何类、变量、函数或其他声明隐藏在封闭作用域中。 [...]

[stmt.label]/1

[...] 标签有自己的命名空间,不会干扰其他标识符 [...]

[cpp.replace]/1

[...] 宏名称只有一个名称空间。 [...]

【讨论】:

    【解决方案2】:

    在 C(6.2.3 标识符的名称空间)中,名称空间的概念定义如下。

    1 如果一个特定标识符的多个声明可见 在翻译单元的任何一点,句法上下文 消除引用不同实体的用法的歧义。因此,有 不同类别标识符的单独名称空间,如 如下:

    — 标签名称(通过标签声明的语法消除歧义 和使用);

    ——结构、联合和枚举的标签(通过 在关键字 struct、union 或 enum 中的 any32) 之后);

    ——结构或工会的成员;每个结构或联合都有一个 其成员的单独名称空间(通过类型消除歧义 用于通过 . 访问成员的表达式。或 -> 运算符);

    ——所有其他标识符,称为普通标识符(在 普通声明符或作为枚举常量)。

    因此,例如,结构标记名称可以与函数名称一致,因为它们属于不同的名称空间。当你用结构标签名指定结构时,你必须使用关键字struct。因此,例如,这些声明不冲突。

    struct s
    {
        int s;
    };
    
    void s( void );
    
    struct s s1;
    

    在这段代码sn-p中,结构的标签名s与函数名s不冲突,因为标签名要用关键字struct指定。

    在 C++ 中,您可以使用不带关键字 struct 的结构标记名称。

    例如

    struct s
    {
        int s;
    };
    
    s s;
    

    是正确的代码。在此声明中

    s s;
    

    声明标识符s的名称隐藏了结构名称。所以如果那么你会写例如

    s s1;
    

    然后编译器将发出错误,因为在此语句中 s 被视为上面声明的标识符的名称。要解决歧义,您需要使用关键字 struct

    struct s
    {
        int s;
    };
    
    s s;
    
    struct s s1;
    

    这在 C++ 20 标准(6.3.1 声明性区域和范围)的以下引用中进行了描述

    4 给定单个声明区域中的一组声明,每个声明 它指定了相同的非限定名称,

    (4.1) — 它们都应该指代同一个实体,或者都指代 函数和函数模板;或

    (4.2)——只有一个声明应该声明一个类名或 不是 typedef 名称的枚举名称和其他声明 都应引用相同的变量、非静态数据成员,或 枚举器,或都指函数和函数模板;在这 如果类名或枚举名被隐藏(6.3.10)。 [ 注意:A 命名空间名称或类模板名称必须是唯一的 声明区域(10.3.2,第 17 条)。 — 尾注 ]

    从引用中可以看出,命名空间名称在其声明区域中必须是唯一的。所以这些声明

    struct Foo { };
    namespace Foo { } 
    

    不正确。

    【讨论】:

      猜你喜欢
      • 2021-01-24
      • 1970-01-01
      • 2015-11-16
      • 2014-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-23
      相关资源
      最近更新 更多