4

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

4

6 回答 6

10

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

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

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

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

(X(X::A));
于 2009-03-25T13:16:58.850 回答
8
X(X::A);

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

(X)(X::A);
于 2009-03-25T13:17:25.683 回答
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);
于 2009-03-25T17:42:16.153 回答
0

您应该将对象声明为

X x(X::A);

代码中的错误。

于 2009-03-25T13:17:51.407 回答
0

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

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

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

于 2009-03-25T13:26:00.093 回答
0

当然,你可以这样做:

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

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

于 2009-03-25T14:09:57.943 回答