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

Jim*_*m V 24 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);
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

mol*_*ilo 38

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

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

int (foo);
int (bar) = 0;
int (baz)(3);
int (twaddle)(baz);
Run Code Online (Sandbox Code Playgroud)

  • K&R解释了为什么允许使用括号. (6认同)
  • [WP:最令人烦恼的解析](https://en.wikipedia.org/wiki/Most_vexing_parse) (6认同)
  • 在一些声明中,如函数指针`int*(*f)();`,您需要使用括号来保持星号与正确的名称相关联.所以他们被允许.当你必须*不*使用它们时,没有规则说明,因此可以随时添加它们. (4认同)

Sta*_*irl 34

问题是代码

Error(value_1);
Run Code Online (Sandbox Code Playgroud)

value_1类型变量的声明Error.

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

例如int *i是指向,int因为它表示表达式*i应该评估为键入int.更多这样的例子:

  • int (*func)()是一个指向函数返回的指针,int因为表达式(*func)()求值为type int.
  • int *p[8]是一个指针数组,int因为表达式*p[x]求值为type int.
  • int (*p)[8]是一个指向8 int'(int[8])数组的指针,因为表达式(*p)[x]求值为type int.
  • int (*(*p[8])())()是一个由指向函数返回指针的函数的8个指针数组,int因为表达式(*(*p[x])())()求值为type int.

类似的int (i)是类型的普通变量,int因为表达式(i)求值为type int.

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

C++在这里应用的规则是将所有可以作为声明的声明视为声明.


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

Error ec();
Run Code Online (Sandbox Code Playgroud)

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


Bo *_*son 13

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

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

Error(value_1);
Run Code Online (Sandbox Code Playgroud)

作为变量声明

Error  value_1;
Run Code Online (Sandbox Code Playgroud)

允许声明具有冗余括号.