为什么允许冗余类名限定符? [英] Why are redundant class name qualifiers allowed?
问题描述
我遇到了这样的代码:
struct A {
A() {}
A(int) {}
};
struct B : A {
void init(int i);
};
void B::init(int i) {
A::A(i); // what is this?
}
int main() {
B b;
b.init(2);
}
这是使用VC11测试版编译和运行的,不带/ W4的错误或警告。
This compiled and ran using VC11 beta with no errors or warnings with /W4.
显而易见的意图是调用B :: init重新初始化B的A基本子对象。我相信它实际上解析为一个变量声明为一个名为 i 的类型为
A
的变量。使用clang编译会生成诊断信息:
The apparent intent is for calling B::init to reinitialize the B's A base subobject. I believe it actually parses as a variable declaration for a new variable named i
with type A
. Compiling with clang produces diagnostics:
ConsoleApplication1.cpp:11:14: warning: declaration shadows a local variable
A::A(i);
^
ConsoleApplication1.cpp:10:22: note: previous declaration is here
void B::init(int i) {
^
ConsoleApplication1.cpp:11:14: error: redefinition of 'i' with a different type
A::A(i);
^
ConsoleApplication1.cpp:10:22: note: previous definition is here
void B::init(int i) {
^
似乎很好奇,类型可以通过冗余类限定来引用。
It seems curious that the type can be referred to with the redundant class qualification.
另外, A :: A(i)
似乎被VS11和clang / gcc解析不同。如果我做 A :: A(b)
clang和gcc创建 b
> A 使用默认构造函数。 VS11错误的说: b
是一个未知的标识符。 VS11似乎解析 A :: A(i)
作为使用构造函数<$ c创建临时 A
$ c> A :: A(int)以 i
作为参数。当消除冗余限定符时,VS将源解析为变量声明,如clang和gcc do,并且产生关于变量 i
的类似错误。
Also, A::A(i)
appears to be parsed differently by VS11 and clang/gcc. If I do A::A(b)
clang and gcc create a variable b
of type A
using the default constructor. VS11 errors out on that saying b
is an unknown identifier. VS11 appears to parse A::A(i)
as the creation of a temporary A
using the constructor A::A(int)
with i
as the parameter. When the redundant qualifier is eliminated VS parses the source as a variable declaration like clang and gcc do, and produces a similar error about shadowing the variable i
.
这种解析的区别解释了为什么VS11会阻塞一个额外的限定符; A :: A :: A :: A(i)
,以及为什么,考虑到clang和gcc可以接受一个额外的限定符,任何数字多于一个额外具有相同
This difference in parsing explains why VS11 will choke on more than a single extra qualifier; A::A::A::A(i)
, and why, given that clang and gcc can accept one extra qualifier, any number more than one extra has the same result as one extra.
这是另一个在不同上下文中使用冗余限定符的例子。所有编译器似乎都解析为临时结构:
Here's another example with the redundant qualifiers in a different context. All compiler seem to parse this as a temporary construction:
class Foo {};
void bar(Foo const &) {}
int main() {
bar(Foo::Foo());
}
- 为什么允许冗余限定符? / li>
- 有一些上下文可以引用构造函数,例如继承构造函数的语法(
class D:B {using B :: B;}; code>)但VS似乎允许它在任何地方。是VS错误,是clang和gcc对如何解析多余的限定符吗?
- 我知道VS在标准合规方面仍然落后,但我确实发现有点令人惊讶现代的,积极开发的编译器可能是如此分歧,在这种情况下,解析冗余限定符作为构造函数的名称(尽管构造函数没有名称),而只是简单地将冗余限定符解析为类型,导致VS构造临时其他人声明一个变量。在
B b(A :: A(i));
被clang和gcc解析为最烦琐的解析,但是VS认为它是声明带有初始化程序的B
类型的变量b
这是否还有很多差异吗? - 很明显,在可移植代码中应该避免使用冗余限定符。是否有很好的方法可以防止此结构被使用?
- Why are redundant qualifiers allowed at all?
- There are some contexts where constructors can be referred to, such as the syntax for inheriting constructors (
class D : B { using B::B; };
) but VS seems to be allowing it anywhere. Is VS wrong and are clang and gcc right in how redundant qualifiers are parsed? - I know VS is still a fair bit behind in terms of standards compliance, but I do find it a bit surprising that modern, actively developed compilers could be so divergent, in this case resolving a redundant qualifier as the name of a constructor (even though constructors don't have names) vs. resolving redundant qualifiers simply to the type, resulting in VS constructing a temporary where the others declare a variable. It can be made even worse where
B b(A::A(i));
is parsed by clang and gcc as the most vexing parse, but VS sees it as declaring a variableb
of typeB
with an initializer. Are there still many differences this severe? - Clearly, redundant qualifiers should be avoided in portable code. Is there a good way to prevent this construct from being used?
推荐答案
可能归因于类名注入,正如ephemient的回答中所指出的,对于这个特定的例子,它已经被C ++语言取消了。
While the phenomenon can probably be attributed to class name injection, as noted in ephemient's answer, for this specific example it has been outlawed by C++ language quite a while ago.
http:/ /www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#147
组合 A :: A
是引用类构造函数所必需的,而不是注入的类名。 A :: A(i)
应该由兼容的编译器解释为涉及构造函数名称的非法(因此无意义)表达式。例如,Comeau编译器将拒绝编译您的代码。
The combination A::A
is required to refer to class constructor, not to the class injected name. The A::A(i)
is supposed to be interpreted by a compliant compiler as an illegal (and therefore meaningless) expression involving constructor name. Comeau compiler, for one example, will refuse to compile your code for that reason.
显然,VC11继续处理 A :: A
作为注入类名的引用。有趣的是,我在VS2005中没有观察到这个问题。
Apparently VC11 continues to treat A::A
as a reference to the injected class name. Interestingly enough, I don't observe this problem in VS2005.
回到 A :: A
被解释为引用注入的名称,可以将 A
对象声明为
Back in the day when A::A
was interpreted as referring to the injected name, one could declare an A
object as
A::A::A::A::A::A a;
等等,任意数字 A
s。但不再。令人惊讶的是,ideone使用的GCC版本(4.3.4?)仍然遇到此问题
and so on, with arbitrary number of A
s. But not anymore. Surprisingly, version of GCC (4.3.4?) used by ideone still suffers from this issue
您可以尝试使用您的VC11版本,看看是否允许。
You can try this with your version of VC11 and see if it allows that.
这篇关于为什么允许冗余类名限定符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!