有哪些名称空间,有哪些规则?


9

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

C ++标准引用了name space,但是我没有看到它的定义。该标准说标签和宏位于不同的名称空间中。所有其他引用name space都在C / C ++兼容性部分中,如下所示(当前草案):

这是C和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

实际的观点是,名称空间是具有所有公共成员(子类)的单例类。请不要私刑我:-)
彼得-恢复莫妮卡

2
@ peterh-ReinstateMonica(再次)阅读了问题
YSC

FWIW,您的链接链接到相关部分:受影响的子句:[class.name] [另请参见[dcl.typedef]] 您可以查看这些部分以了解规则的工作方式。
NathanOliver

至少有两个名称空间:一个用于标签[stmt.label]/1,一个用于宏[cpp]/8
YSC

1
(对我而言)有趣的是,说明和示例都显示了与基本原理相反的内容;隐藏非类型名称的类型名称。考虑到状态草案,我希望该段可以更改。
molbdnilo

Answers:


2

命名空间项可以更完善的ISO C标准; 引用ISO C11

6.2.3标识符的命名空间

如果在翻译单元中的任何位置都可以看到一个以上的特定标识符声明,则语法上下文会消除指向不同实体的用法的歧义。因此,对于各种类别的标识符,存在单独的名称空间,如下所示:

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

但是,C ++ 的名称空间定义并不是最近才有的,自从ISO C ++标准于'98引入以来,就已经在[diff.class] / 1中以其当前形式进行了描述。根据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

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


1

在C(6.2.3标识符的名称空间)中,名称空间的概念通过以下方式定义。

1如果在翻译单元中的任何位置都可以看到一个以上的特定标识符声明,则语法上下文会使引用不同实体的用法变得含糊不清。因此,对于各种类别的标识符,存在单独的名称空间,如下所示:

—标签名称(由标签声明和使用的语法消除);

—关键字struct,union或enum的结构,联合和枚举的标签(通过跟随any32消除歧义);

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

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

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

struct s
{
    int s;
};

void s( void );

struct s s1;

在此代码段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 Standard引用(6.3.1声明性区域和范围)中对此进行了描述。

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

(4.1)—它们都应指代同一个实体,或者均指功能和功能模板;要么

(4.2)—恰好一个声明应声明不是typedef名称的类名或枚举名,而其他声明应全部指代相同的变量,非静态数据成员或枚举器,或全部指代函数和函数模板; 在这种情况下,类名称或枚举名称是隐藏的(6.3.10)。[ 注意:名称空间名称或类模板名称在其声明性区域中必须是唯一的(10.3.2,第17章)。—尾注 ]

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

struct Foo { };
namespace Foo { } 

是不正确的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.