C ++枚举未正确识别编译器
-
22-08-2019 - |
题
谁能解释为什么以下代码不编译(ON G ++(GCC)3.2.3 20030502(Red Hat Linux 3.2.3-49))?
struct X {
public:
enum State { A, B, C };
X(State s) {}
};
int main()
{
X(X::A);
}
我收到的消息是:
jjj.cpp:在函数'int main()'中:
jjj.cpp:10:'xx :: a'不是'struct x'的静态成员
jjj.cpp:10:无匹配函数呼叫'x :: x()'
jjj.cpp:1:候选人是:x :: x(const x&)
jjj.cpp:5:x :: x(x :: state)`
这是不良代码还是编译器错误?
Neil+Konrad解决的问题。请参阅下面尼尔回答的评论。
解决方案
X(X::A);
正在被视为ASA函数声明。如果您真的想要此代码,请使用:
(X)(X::A);
其他提示
您已经忘记了定义中的变量名称:
int main()
{
X my_x(X::A);
}
您的代码使编译器感到困惑,因为从语法上它无法将其与函数声明区分开(返回 X
和过去 X::A
作为论点)。如有疑问,C ++编译器始终会歧义声明。
解决方案是在周围引入多余的括号 X
由于编译器禁止括号围绕类型(而不是构造电话等):
(X(X::A));
只是为了使晶体清楚发生。看这个示例
int main() {
float a = 0;
{
int(a); // no-op?
a = 1;
}
cout << a;
}
它会输出什么?好吧,它将输出 0
. 。这 int(a)
以上可以通过两种不同的方式解析:
- 铸造并丢弃结果
- 声明一个称为的变量
a
. 。但是忽略标识符周围的括号。
当出现这种情况时,该编译器在语句中使用了函数式演员表,并且看起来也像是声明时,它将始终将其视为声明。当句法上不能是声明(编译器将查看整个行以确定这一点)时,它将被视为表达式。因此,我们正在分配内部 a
上面,离开外部 a
在零。
现在,您的情况就是这样。您正在尝试(偶然地)声明一个名称的标识符 A
在一个称为的课堂中 X
:
X (X::A); // parsed as X X::A;
然后,编译器继续抱怨未声明为默认构造函数,因为静态是默认的。但是,即使您有X的默认构造函数,它当然仍然是错误的,因为 A
是X的静态成员,也可以在块范围内定义/声明X的静态成员。
你可以做到 不是 通过做几件事,看起来像是声明。首先,您可以帕伦(Paren)整个表达式,这使得它看起来不再像声明了。或者只是paren铸造的类型。其他答案中都提到了这两种歧义:
(X(X::A)); (X)(X::A)
当您尝试实际声明对象时,存在类似但独特的歧义。看看这个示例:
int main() {
float a = 0;
int b(int(a)); // object or function?
}
因为 int(a)
可以是称为参数的声明 a
浮点变量的明确转换为int,编译器再次决定这是声明。因此,我们碰巧声明了一个称为的函数 b
, ,它采用整数参数并返回整数。基于以上的歧义,有几种可能歧义的可能性:
int b((int(a))); int b((int)a);
您应该将一个对象声明为
X x(X::A);
代码中的错误。
这两条线中的任何一个都对我有用:
X obj(X::A);
X obj2 = X(X::A);
正如尼尔·巴特沃思(Neil Butterworth)指出的那样, X(X::A)
被视为函数声明。如果您真的想要一个匿名对象, (X)(X::A)
将构造X对象并立即删除它。
当然,您可以做这样的事情:
int main()
{
// code
{
X temp(X::A);
}
// more code
}
这将更加可读性,并且基本上具有相同的效果。