代码之家  ›  专栏  ›  技术社区  ›  Ari

编译器不能正确识别C++枚举

  •  4
  • Ari  · 技术社区  · 16 年前

    有人能解释一下为什么以下代码不能编译(在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解决了这个问题。请参阅下面对尼尔答案的评论。

    6 回复  |  直到 16 年前
        1
  •  8
  •   anon    16 年前
    X(X::A);
    

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

    (X)(X::A);
    
        2
  •  10
  •   Konrad Rudolph    16 年前

    您在定义中忘记了变量名:

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

    您的代码混淆了编译器,因为在语法上它无法将其与函数声明(返回 X 通过 X::A 作为一个论点)。当有疑问时,C++编译器总是消除歧义,支持声明。

    解决方案是在 X 因为编译器禁止在类型周围使用括号(而不是构造函数调用等):

    (X(X::A));
    
        3
  •  1
  •   Johannes Schaub - litb    16 年前

    只是为了让它清楚地知道发生了什么。看看这个例子

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

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

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

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

    现在,你的情况正是如此。您试图(不小心)声明一个名为 A 在一个名为 X :

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

    然后,编译器继续抱怨一个未声明的默认构造函数,因为静态(正如它假定的那样)是默认构造的。但是即使您有一个x的默认构造函数,它当然仍然是错误的,因为两者都不是 是x的静态成员,也不能在块范围内定义/声明x的静态成员。

    你可以做到 做几件事就像一个宣言。首先,您可以削减整个表达式,使其不再像声明。或者只需将类型转换为。其他答案中提到了这两种消除歧义的方法:

    (X(X::A)); (X)(X::A)
    

    当您试图实际声明一个对象时,有一个相似但明显的歧义。看看这个例子:

    int main() {
        float a = 0;
        int b(int(a)); // object or function?
    }
    

    因为 int(a) 不能同时是调用的参数的声明 浮点变量的显式转换(强制转换)为int,编译器再次决定这是一个声明。因此,我们碰巧声明了一个函数 b ,它接受一个整数参数并返回一个整数。根据上述消除歧义的方法,有几种消除歧义的方法:

    int b((int(a))); int b((int)a);
    
        4
  •  0
  •   Marcin Gil    16 年前

    您应该将对象声明为

    X x(X::A);
    

    代码中有错误。

        5
  •  0
  •   Chris AtLee    16 年前

    这两行中的任何一行对我都有效:

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

    尼尔·巴特沃斯指出, X(X::A) 正在被视为函数声明。如果你真的想要匿名对象, (X)(X::A) 将构造一个X对象并立即将其删除。

        6
  •  0
  •   rlbond    16 年前

    当然,你可以这样做:

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

    这将更易于阅读,并且基本上具有相同的效果。