【问题标题】:C++ enum not properly recognized by compiler编译器无法正确识别 C++ 枚举
【发布时间】:2009-03-25 13:12:54
【问题描述】:

谁能解释为什么以下代码无法编译(在 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 的答案。

【问题讨论】:

    标签: c++ enums constructor temporary


    【解决方案1】:

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

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

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

    解决方案是在 X 周围引入多余的括号,因为编译器禁止在类型周围使用括号(与构造调用等相反):

    (X(X::A));
    

    【讨论】:

    • 啊,不,实际上。我正在尝试创建一个临时的。如果我添加另一个构造函数,比如 X(int a) {},我可以做 X(5);它编译得很好。只有枚举会引起麻烦。
    • 我已经更新了我的答案,并给出了 Neil 解决方案的替代方案。
    • 请看我对尼尔的评论。
    【解决方案2】:
    X(X::A);
    

    被视为一个函数声明。如果您真的想要此代码,请使用:

    (X)(X::A);
    

    【讨论】:

    • 括号当然可以解决问题,但我不确定如何将其视为函数声明,因为 X::A 不是类型。从句法上讲,它可以是一个类型,但是 X x(X::A) 将同样模棱两可。
    • 我对错误信息的解读是编译器认为它是一个被复制构造的匿名对象。这就是为什么它谈论“X X::A”而不是简单的“X::A”。但我不明白它为什么会这样想。
    • Ari:我自己实际上对错误消息感到困惑,因为当你省略所有括号时它是相同的,这显然(对于编译器)是一个变量声明(X 类型的 A,在范围内X)。但根据标准,它应该被编译器视为函数声明。
    • 康拉德,我想你成功了。它忽略了括号并将其视为 var decl。这与解释模板中需要 typename 的问题相同。
    • X(X::A)
    【解决方案3】:

    只是为了弄清楚会发生什么。看这个例子

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

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

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

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

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

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

    【讨论】:

      【解决方案4】:

      你应该将一个对象声明为

      X x(X::A);
      

      代码中的错误。

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

          当然,你可以这样做:

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

          这样会更易读,效果基本一样。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-01-12
            • 1970-01-01
            • 2014-08-17
            相关资源
            最近更新 更多