C++ 为什么我不能使用双冒号在命名空间中向前声明一个类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2059665/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't I forward-declare a class in a namespace using double colons?
提问by John Dibling
class Namespace::Class;
Why do I have to do this?:
为什么我必须这样做?:
namespace Namespace {
class Class;
}
Using VC++ 8.0, the compiler issues:
使用 VC++ 8.0,编译器问题:
error C2653: 'Namespace' : is not a class or namespace name
错误 C2653:“命名空间”:不是类或命名空间名称
I assume that the problem here is that the compiler cannot tell whether Namespace
is a class or a namespace? But why does this matter since it's just a forward declaration?
我认为这里的问题是编译器无法分辨Namespace
是类还是命名空间?但为什么这很重要,因为它只是一个前向声明?
Is there another way to forward-declare a class defined in some namespace? The syntax above feels like I'm "reopening" the namespace and extending its definition. What if Class
were not actually defined in Namespace
? Would this result in an error at some point?
有没有另一种方法来向前声明在某个命名空间中定义的类?上面的语法感觉就像我在“重新打开”命名空间并扩展其定义。如果Class
实际上没有在 中定义Namespace
怎么办?这会在某些时候导致错误吗?
采纳答案by AnT
Because you can't. In C++ language fully-qualified names are only used to refer to existing(i.e. previously declared) entities. They can't be used to introduce newentities.
因为你不能。在 C++ 语言中,完全限定名称仅用于引用现有(即先前声明的)实体。它们不能用于引入新实体。
And you arein fact "reopening" the namespace to declare new entities. If the class Class
is later defined as a member of different namespace - it is a completely different class that has nothing to do with the one you declared here.
而您实际上是在“重新打开”命名空间以声明新实体。如果该类Class
后来被定义为不同命名空间的成员 - 它是一个完全不同的类,与您在此处声明的类无关。
Once you get to the point of definingthe pre-declared class, you don't need to "reopen" the namespace again. You can define it in the global namespace (or any namespace enclosing your Namespace
) as
一旦到达定义预先声明的类的地步,就不需要再次“重新打开”命名空间。您可以在全局命名空间(或包含您的 的任何命名空间Namespace
)中将其定义为
class Namespace::Class {
/* whatever */
};
Since you are referring to an entity that has already been declared in namespace Namespace
, you can use qualified name Namespace::Class
.
由于您指的是已在命名空间中声明的实体,因此Namespace
您可以使用限定名称Namespace::Class
。
回答by John Dibling
You're getting correct answers, let me just try re-wording:
你得到了正确的答案,让我试着重新措辞:
class Namespace::Class;
class Namespace::Class;
Why do I have to do this?
为什么我必须这样做?
You have to do this because the term Namespace::Class
is telling the compiler:
您必须这样做,因为该术语Namespace::Class
告诉编译器:
...OK, compiler. Go find the namespace named Namespace, and within that refer to the class named Class.
...好的,编译器。找到名为 Namespace 的命名空间,并在其中引用名为 Class 的类。
But the compiler doesn't know what you're talking about because it doesn't know any namespace named Namespace
. Even if there were a namespace named Namespace
, as in:
但是编译器不知道你在说什么,因为它不知道任何名为Namespace
. 即使有一个名为 的命名空间Namespace
,如:
namespace Namespace
{
};
class Namespace::Class;
it still wouldn't work, because you can't declare a class within a namespace from outside that namespace. You have to be in the namespace.
它仍然不起作用,因为您无法从该名称空间外部声明该名称空间内的类。你必须在命名空间中。
So, you can in fact forward declare a class within a namespace. Just do this:
因此,您实际上可以在命名空间中转发声明一个类。只需这样做:
namespace Namespace
{
class Class;
};
回答by Igor Zevaka
I suppose it's for the same reason you cannot declare nested namespaces in one go like this:
我想这与您不能像这样一次性声明嵌套命名空间的原因相同:
namespace Company::Communications::Sockets {
}
and you have to do this:
你必须这样做:
namespace Company {
namespace Communications {
namespace Sockets {
}
}
}
回答by Martin G
It would not be clear what a forward declared variable's type actually is. The forward declaration class Namespace::Class;
could mean
不清楚前向声明变量的类型究竟是什么。预先声明class Namespace::Class;
可能意味着
namespace Namespace {
class Class;
}
or
或者
class Namespace {
public:
class Class;
};
回答by StoryTeller - Unslander Monica
There's a lot of excellent answers about the rationale involved in disallowing it. I just want to provide the boring standardese clause the specifically prohibits it. This holds true for C++17 (n4659).
关于禁止它所涉及的理由,有很多很好的答案。我只想提供无聊的标准条款,明确禁止它。这适用于 C++17 (n4659)。
The paragraph in question is [class.name]/2:
有问题的段落是[class.name]/2:
A declaration consisting solely of class-key identifier; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name. It introduces the class name into the current scope.
仅由类键标识符组成的声明;要么是在当前范围内重新声明名称,要么是作为类名的标识符的前向声明。它将类名引入当前作用域。
The above defines what constitutes a forward declaration (or redclaration of a class). Essentially, it must be one of class identifier;
, struct identifier;
or union identifier;
where identiferis the common lexical definition in [lex.name]:
以上定义了什么构成了前向声明(或类的红色声明)。本质上,它必须是其中之一class identifier;
,struct identifier;
或者union identifier;
其中identifer是[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
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
Which is the production of the common scheme [a-zA-Z_][a-zA-Z0-9_]*
we are all familiar with. As you can see, this precludes class foo::bar;
from being a valid forward declaration, because foo::bar
is not an identifier. It's a fully qualified name, something different.
这就是[a-zA-Z_][a-zA-Z0-9_]*
我们都熟悉的通用方案的制作。正如你所看到的,这排除class foo::bar;
了一个有效的前向声明,因为foo::bar
它不是一个标识符。这是一个完全限定的名称,有所不同。