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

Why doesn't this enum convert to int?

本文关键字:int 转换 枚举 为什么      更新时间:2023-10-16

为什么下面的代码不能在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 链接)

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

这与"最令人烦恼的解析"来自同一个地方 - 如果它可以是一个声明,它就是一个声明的规则。
令人惊讶的是,您可以在变量声明中的标识符周围加上括号。
(我不知道为什么,但我猜它简化了C的解析器。

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

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

问题是代码

Error(value_1);

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

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

例如,int *i是指向int的指针,因为它表示表达式*i的计算结果应为 键入int。更多这样的例子:

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

类似地,int (i)int类型的普通变量,作为表达式(i)计算结果为int类型。

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

C++在这里应用的规则说,将所有可以成为声明的东西都视为声明。


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

Error ec();

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

main.cpp:19:18: error: 没有匹配函数来调用 'Error::Error()'
Error(value_1);

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

Error(value_1);

作为变量声明

Error  value_1;

声明允许有多余的括号。