C++ 为什么可以';我是否使用双冒号在命名空间中向前声明一个类?

C++ 为什么可以';我是否使用双冒号在命名空间中向前声明一个类?,c++,namespaces,C++,Namespaces,我为什么要这么做 class Namespace::Class; 使用VC++8.0时,编译器会出现以下问题: 错误C2653:“命名空间”:不是类或命名空间名称 我假设这里的问题是编译器无法判断名称空间是类还是名称空间?但既然这只是一个前瞻性声明,为什么这很重要呢 是否有其他方法可以向前声明某个命名空间中定义的类?上面的语法感觉像是在“重新打开”名称空间并扩展其定义。如果类不是在名称空间中实际定义的,该怎么办?这会在某个时候导致错误吗?因为您不能。在C++语言中,完全限定名仅用于引用现有的(

我为什么要这么做

class Namespace::Class;
使用VC++8.0时,编译器会出现以下问题:

错误C2653:“命名空间”:不是类或命名空间名称

我假设这里的问题是编译器无法判断
名称空间
是类还是名称空间?但既然这只是一个前瞻性声明,为什么这很重要呢


是否有其他方法可以向前声明某个命名空间中定义的类?上面的语法感觉像是在“重新打开”名称空间并扩展其定义。如果
不是在
名称空间
中实际定义的,该怎么办?这会在某个时候导致错误吗?

因为您不能。在C++语言中,完全限定名仅用于引用现有的(即先前声明的)实体。它们不能用于引入新实体

实际上,您正在“重新打开”名称空间以声明新实体。如果类
class
后来被定义为不同名称空间的成员,那么它是一个完全不同的类,与您在此处声明的类无关

一旦定义了预先声明的类,就不需要再次“重新打开”名称空间。您可以在全局命名空间(或包含
命名空间的任何命名空间
)中将其定义为


由于您所指的实体已在命名空间
命名空间中声明
,因此可以使用限定名称
命名空间::Class
,您得到了正确的答案,让我尝试重新措辞:

类名称空间::类

我为什么要这么做

您必须这样做,因为术语
Namespace::Class
告诉编译器:

…好的,编译器。去找那个 名称空间命名为namespace,并且在 引用名为class的类的

但是编译器不知道您在说什么,因为它不知道任何名为
namespace
的名称空间。即使存在名为
名称空间
的名称空间,如:

class Namespace::Class {
  /* whatever */
};
它仍然不起作用,因为不能从名称空间之外声明名称空间内的类。您必须位于名称空间中

因此,实际上可以在名称空间中向前声明一个类。只要这样做:

namespace Namespace
{
};

class Namespace::Class;

我想这与您不能像这样一次性声明嵌套命名空间的原因相同:

namespace Namespace
{
    class Class;
};
你必须这样做:

namespace Company::Communications::Sockets {
}

关于否决它的理由,有很多很好的答案。我只想提供无聊的标准条款,明确禁止它。这对于C++17(n4659)也是如此

有关段落是:

仅由类密钥标识符组成的声明;要么是一个 在当前作用域或转发中重新声明名称 将标识符声明为类名。它介绍了这门课 将名称添加到当前范围中

上面定义了构成转发声明(或类的重声明)的内容。本质上,它必须是
类标识符之一
结构标识符
联合标识符其中identifer是中的常用词汇定义:


这是我们都熟悉的通用方案的产生。如您所见,这排除了
类foo::bar
不是有效的转发声明,因为
foo::bar
不是标识符。这是一个完全限定的名称,有些不同。

不清楚前向声明变量的实际类型。前向声明
classnamespace::class可能意味着

identifier:
  identifier-nondigit
  identifier identifier-nondigit
  identifier digit
identifier-nondigit:
  nondigit
  universal-character-name
nondigit: one of
  a b c d e f g h i j k l m
  n o p q r s t u v w x y z
  A B C D E F G H I J K L M
  N O P Q R S T U V W X Y Z _
digit: one of
  0 1 2 3 4 5 6 7 8 9


@STingRaySC:向前声明嵌套类的唯一方法是将声明放在封闭类的定义中。在定义封闭类之前,确实没有办法向前声明嵌套类。@STingRaySC:可以fwd声明嵌套类--请参见我的答案。@John Dibling:嵌套类是在另一个类中声明的类。在命名空间中立即声明的类不是嵌套类。你的答案中没有关于感官类的内容。让我不同意这里所有的答案,并说这只是语言的一个设计缺陷。他们可以更好地思考。这是在讨论为什么C++是非法的(这是主观的),而且它看起来是有争论性的。编译器应该知道在代码> A::B:<代码> > <代码> <代码>是命名空间标识符而不是类名?@ StnGraySc:讨论是主观的,因为没有一个明确的答案,为什么C++会这样做,所以我们在推测。(问题是一个散弹枪问题,其中一些问题已经被回答了。)在这一点上,我对争论的痕迹变得敏感,你同意帕维尔的观点,这是C++的一个错误特性。如果
Namespace
是一个类或名称空间,那么我不会有任何疑问。只是不要接近可能引发语法语言大战的暗示。所有其他答案都让我感到困惑,但“你不能从名称空间之外声明名称空间内的类。你必须在名称空间中。”这是一个非常有用的提示,需要记住。这实际上不是一个解释为什么你不能这样做的答案。这是一个节省了我大量时间的答案C++17添加了这个。在这里,你知道所有的都是名称空间。但是对于Company::Communications::Socket类,您不知道通信是一个名称空间还是一个类(其中Socket是嵌套类)。不是吗?我认为这是最好的答案之一,因为它回答了为什么编译器本身无法轻松确定这一点。
namespace Company {
  namespace Communications {
    namespace Sockets {
    }
  }
}
identifier:
  identifier-nondigit
  identifier identifier-nondigit
  identifier digit
identifier-nondigit:
  nondigit
  universal-character-name
nondigit: one of
  a b c d e f g h i j k l m
  n o p q r s t u v w x y z
  A B C D E F G H I J K L M
  N O P Q R S T U V W X Y Z _
digit: one of
  0 1 2 3 4 5 6 7 8 9
namespace Namespace {
  class Class;
}
class Namespace {
public:
  class Class;
};