编译器无法正确识别C ++枚举

时间:2009-03-25 13:12:55

标签: c++ enums constructor temporary

任何人都可以解释为什么以下代码无法编译(在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:'X X :: A'不是'struct X'的静态成员 jjj.cpp:10:没有用于调用'X :: X()'的匹配函数 jjj.cpp:1:候选者是:X :: X(const X&)
jjj.cpp:5:X :: X(X :: State)`

这是错误的代码还是编译器错误?

Neil + Konrad解决了问题。请参阅下面对Neil的回答的评论。

6 个答案:

答案 0 :(得分:10)

您忘记了定义中的变量名称:

int main()
{
   X my_x(X::A);
}

您的代码会混淆编译器,因为它在语法上无法将其与函数声明区分开来(返回X并将X::A作为参数传递)。如果有疑问,C ++编译器总是消除歧义,支持声明。

解决方案是在X周围引入冗余括号,因为编译器禁止围绕类型的括号(而不是构造调用等):

(X(X::A));

答案 1 :(得分:8)

X(X::A);

被视为一个函数声明。如果您确实需要此代码,请使用:

(X)(X::A);

答案 2 :(得分:1)

只是为了清楚地说明发生了什么。看看这个例子

int main() {
    float a = 0;
    {
        int(a); // no-op?
        a = 1;
    }
    cout << a;
}

它会输出什么?好吧,它会输出0。上面的int(a)可以用两种不同的方式解析:

  • 转换为int并放弃结果
  • 声明一个名为a的变量。但忽略标识符周围的括号。

编译器,当出现这样的情况,其中在语句中使用函数样式转换并且它看起来像声明时,将始终将其作为声明。当它在语法上不能成为一个声明时(编译器会查看整行来确定它),它将被视为一个表达式。因此,我们分配给上面的内部a,将外部a保留为零。

现在,你的情况恰恰如此。您正在尝试(意外地)在名为A的类中声明名为X的标识符:

X (X::A); // parsed as X X::A;

然后编译器继续抱怨一个未声明的默认构造函数,因为它假设的静态是默认构造的。但即使你有一个X的默认构造函数,它当然仍然是错误的,因为A都不是X的静态成员,也不能在块作用域中定义/声明X的静态。

你可以通过做几件事来使看起来像一个声明。首先,你可以掌握整个表达式,这使得它看起来不再是一个声明了。或者只是改变投射的类型。其他答案都提到了这两种消歧:

(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);

答案 3 :(得分:0)

您应该将对象声明为

X x(X::A);

代码中的错误。

答案 4 :(得分:0)

这两行中的任何一条都适合我:

X obj(X::A);
X obj2 = X(X::A);

正如Neil Butterworth指出的那样,X(X::A)被视为功能声明。如果你真的想要一个匿名对象,(X)(X::A)将构造一个X对象并立即删除它。

答案 5 :(得分:0)

当然,你可以做这样的事情:

int main()
{
    // code
    {
    X temp(X::A);
    }
    // more code
}

这将更具可读性,基本上具有相同的效果。