为什么这个枚举不能转换为int?

时间:2017-12-01 15:27:08

标签: c++ enums

为什么下面的代码不能在g ++(C ++ 14),MSVC(C ++ 14)或ARM(C ++ 03)下编译?

命名的Error实例调用整数构造函数,但匿名的Error实例无法解析。

class Error
{
public:
    Error(int err) : code_(err) {}
    const int code_;
};

enum Value
{
    value_1
};

int main()
{
    // compiles
    Error e(value_1);

    // does not compile under G++, ARM, or MSVC
    Error(value_1);
}

G ++下的示例错误:(Coliru link

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out

main.cpp: In function 'int main()':
main.cpp:19:18: error: no matching function for call to 'Error::Error()'
     Error(value_1);
                  ^
main.cpp:4:5: note: candidate: Error::Error(int)
     Error(int err) : code_(err) {}
     ^~~~~
main.cpp:4:5: note:   candidate expects 1 argument, 0 provided
main.cpp:1:7: note: candidate: constexpr Error::Error(const Error&)
 class Error
       ^~~~~
main.cpp:1:7: note:   candidate expects 1 argument, 0 provided
main.cpp:1:7: note: candidate: constexpr Error::Error(Error&&)
main.cpp:1:7: note:   candidate expects 1 argument, 0 provided

3 个答案:

答案 0 :(得分:37)

这来自与“最令人烦恼的解析”相同的地方 - 规则如果它可以是声明,则 是声明。
令人惊讶的是,您可以在变量声明中围绕标识符放置括号 (我不知道为什么,但我猜它在当天简化了C的解析器。)

以下是int变量的所有有效声明:

int (foo);
int (bar) = 0;
int (baz)(3);
int (twaddle)(baz);

答案 1 :(得分:33)

问题在于代码

Error(value_1);

是类型为value_1的变量Error的声明。

这是C语言的遗产,它使用表达式作为类型声明的一部分。

例如int *i是指向int的指针,因为它表示表达式*i应评估为int类型。更多这方面的例子:

  • int (*func)()是指向返回int的函数的指针,因为表达式(*func)()的计算结果为int
  • int *p[8]是指向int的指针数组,因为表达式*p[x]的计算结果为int
  • int (*p)[8]是指向8个int'(int[8])数组的指针,因为表达式(*p)[x]的计算结果为int
  • int (*(*p[8])())()是一个包含8个指向函数的数组,这些函数返回指向返回int的函数的指针,因为表达式(*(*p[x])())()的计算结果为int

同样,int (i)int类型的普通变量,因为表达式(i)的计算结果为int

因为C ++从C继承了它,所以它使用括号作为类型声明的一部分,但也会在顶部添加更多语法,从而导致一些意想不到的结果。

C ++在此处应用的规则是将所有可以作为声明的声明视为声明。

如果经常由这样的代码引起类似的混淆:

Error ec();

是函数ec的前向声明,返回Error

答案 2 :(得分:13)

  

main.cpp:19:18:错误:没有匹配函数来调用'错误::错误()'
      误差(值_1);

编译器尝试调用不存在的默认构造函数Error::Error(),因为它看到了

Error(value_1);

作为变量声明

Error  value_1;

允许声明具有冗余括号。