为什么下面的代码不能在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
答案 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;
允许声明具有冗余括号。