class Namespace::Class;
为什么我必须这样做?:
namespace Namespace {
class Class;
}
使用VC ++ 8.0,编译器会发出:
错误C2653:'Namespace':不是类或命名空间名称
我认为这里的问题是编译器无法判断Namespace
是类还是命名空间?但是为什么这很重要,因为它只是一个前瞻性声明?
还有另一种方法来转发声明在某个命名空间中定义的类吗?上面的语法感觉就像我“重新打开”命名空间并扩展其定义。如果Class
中实际未定义Namespace
怎么办?这会在某个时候导致错误吗?
答案 0 :(得分:184)
你得到了正确的答案,让我试着重新措辞:
class Namespace::Class;
为什么我必须这样做?
你必须这样做,因为术语Namespace::Class
告诉编译器:
......好的,编译器。去寻找 名为Namespace的名称空间,并在其中 引用名为Class的类。
但编译器不知道你在说什么,因为它不知道任何名为Namespace
的命名空间。即使有一个名为Namespace
的命名空间,如:
namespace Namespace
{
};
class Namespace::Class;
它仍然无效,因为您无法在该命名空间外部声明命名空间中的类。你必须在名称空间中。
因此,您实际上可以在命名空间中转发声明一个类。就这样做:
namespace Namespace
{
class Class;
};
答案 1 :(得分:82)
因为你做不到。在C ++语言中,完全限定名称仅用于引用现有(即先前声明的)实体。它们不能用于引入 new 实体。
实际上“重新打开”命名空间以声明新实体。如果稍后将类Class
定义为不同命名空间的成员 - 它是一个完全不同的类,与您在此处声明的类无关。
一旦你到达定义预先声明的类,你就不需要再次“重新打开”命名空间。您可以在全局命名空间(或包含Namespace
的任何命名空间)中将其定义为
class Namespace::Class {
/* whatever */
};
由于您指的是已在命名空间Namespace
中声明的实体,因此您可以使用限定名称Namespace::Class
。
答案 2 :(得分:21)
我认为这是出于同样的原因,你不能像这样一次声明嵌套命名空间:
namespace Company::Communications::Sockets {
}
你必须这样做:
namespace Company {
namespace Communications {
namespace Sockets {
}
}
}
答案 3 :(得分:2)
尚不清楚前向声明的变量的类型实际上是什么。前向声明class Namespace::Class;
可能意味着
namespace Namespace {
class Class;
}
或
class Namespace {
public:
class Class;
};
答案 4 :(得分:0)
关于禁止它的理由,有很多很好的答案。我只是想提供无聊的标准条款,具体禁止它。这适用于C ++ 17(n4659)。
有问题的段落是[class.name]/2:
仅由类密钥标识符组成的声明;是一个 重新声明当前范围内的名称或转发 将标识符声明为类名。它介绍了这门课程 命名为当前范围。
以上定义了什么构成了前瞻性声明(或类的重新声明)。从本质上讲,它必须是class identifier;
,struct identifier;
或union identifier;
中的一个,其中标识符是[lex.name]中常见的词汇定义:
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
我们都熟悉的常见方案[a-zA-Z_][a-zA-Z0-9_]*
的制作。如您所见,这使class foo::bar;
无法成为有效的前向声明,因为foo::bar
不是标识符。这是一个完全合格的名字,不同的东西。