C++ C++;11单个限定名称和两个连续名称之间的歧义?

C++ C++;11单个限定名称和两个连续名称之间的歧义?,c++,c++11,C++,C++11,下面的C++11程序是否格式错误 struct a { struct b { }; void f() {}; }; extern struct a b; struct a ::b; int main() { b.f(); } 为什么 有趣的是这一行: struct a ::b; 这是内部类a::b的前向声明吗 或者这是全局变量b的定义?相当于: struct a (::b); 结构a::b不会声明类型为a的名为b的变量,如果您是这样要求的话。它是嵌套类型a

下面的C++11程序是否格式错误

struct a
{
    struct b {  };

    void f() {};
};

extern struct a b;

struct a ::b;

int main()
{
    b.f();
}
为什么

有趣的是这一行:

struct a ::b;
这是内部类
a::b
的前向声明吗

或者这是全局变量
b
的定义?相当于:

struct a (::b);

结构a::b不会声明类型为
a
的名为
b
的变量,如果您是这样要求的话。它是嵌套类型
a::b
的(冗余)前向声明。在C++程序中,空白并不普遍意义重大。因此,您的程序声明但从未定义名为
b
的变量。这违反了一条定义规则:因此程序的格式不正确,链接器也会告诉你同样的内容。

Take 2


结构a::b是结构a::b的格式良好的声明

它不是转发声明,因为结构a::b已被 定义该标准没有正式定义远期申报,但 被普遍接受的意思是在某事物之前和之后的声明 与它的定义是分开的

它也不是全局变量
b
的声明

空格是无关紧要的,因此为了使假定的声明 有建议的模糊性

/*A*/ struct a::b;
当然也会有同样的歧义。像那样重写,我们可能 我们同意,宣言的含义是显而易见的;但我们会 我想知道这个明显的意义是否被标准所证实

我将只考虑C++11标准。(我认为这是一项决议 C++03标准中的一个问题实际上更简单)

该标准将一元范围运算符
与范围运算符区分开来 解析运算符

§3.4.3限定名称查找,第1段:

类或命名空间成员或枚举数的名称可以在::scope解析后引用 运算符(5.1)应用于表示其类、命名空间或枚举的嵌套名称说明符

§3.4.3限定名称查找,第4段:

以一元范围运算符为前缀的名称::(5.1)在全局范围内的翻译单元中查找 在哪里使用它

这些引文并不是为了解释这种区别,只是为了表明这一点 它存在。但它们立即提供了一个要点,即在
/*A*/
运营商必须是§3.4.3/4中的一元范围运营商 维持全局-
::b
/*A*/
的解释

显然,
/*A*/
中的作用域运算符不是 一元的。但我们参考§5.1主要表达,了解更多信息 一元范围运算符和范围的语法定义 解析运算符,无论如何,我们还没有看到关于 当if是作用域的右操作数时,查找
b
解析运算符

在§5.1.1/8中,我们发现操作员
被定义为 §3.4.3/1中的中缀运算符,也作为 §3.4.3/4在合格id语法中:

当中缀运算符是一个字符的最终标记时,它就是中缀运算符 嵌套名称说明符,后跟
模板
,以及 然后是一个非限定id,否则它是 背景:

:: identifier
:: operator-function-id
:: literal-operator-id
:: template-id
根据此语法,
运算符必须与 嵌套名称说明符(构成范围解析运算符),如果 它可以。根据语法,
/*a*/
中的
a::
是嵌套的名称说明符 而
a::b
是第一种形式的限定id 嵌套名称说明符模板[opt]unqualified-id

因此,我们确信§3.4.3限定名称查找适用于中的
b
/*A*/
,可参考§3.4.3.1类成员,第1段, 对于该上下文中的
b
应在
a
中查找,而不是在全局中查找的结论:

如果限定id的嵌套名称说明符指定类,则在嵌套名称之后指定的名称- 在类(10.2)的范围内查找说明符,下面列出的情况除外

“下列情况”均不适用于
/*A*/
,如果有任何疑问 嵌套类
a::b
算作
a
,§9.2类成员的一个成员, 第1款将其删除:

类的成员包括数据成员、成员函数(9.3)、嵌套类型和 统计员

发现
a::b
错误地要求在
a
中查找
b
/*A*/
格式良好的问题变成了是否
/*A*/
是每个标准的声明(当然是
struct A;
) 地点是)

是的,我们可以通过以下几个步骤来确保这一点: 声明语法:-

  • 根据§7声明第1段,声明可以是简单声明, 一个简单的声明可以是decl说明符seq

  • 根据§7.1说明符第1段,decl说明符seq可以是decl说明符, decl说明符可以是类型说明符

  • 根据§7.1.6类型说明符第1段,类型说明符可以是 详细的类型说明符

  • 根据§7.1.6.3详细类型说明符,第0段,详细类型说明符 可能是:

    类键属性说明符seq[opt]嵌套名称说明符[opt]标识符

其中类键为
class
struct
union
(根据§9,第1段) 和可选属性
:: identifier
:: operator-function-id
:: literal-operator-id
:: template-id
class-key nested-name-specifier identifier
error: forward declaration of struct cannot have a nested name specifier
error: use of undeclared identifier 'a'
warning: declaration ‘struct a::b’ does not declare anything
undefined reference to `b'