C++ 为什么';t这是C++;表达式甚至生成警告?

C++ 为什么';t这是C++;表达式甚至生成警告?,c++,casting,void,C++,Casting,Void,我知道您可以取消“表达式无效”警告,使表达式无效: int main() { void(2+3); } 如果我没有错的话,将某个对象强制转换为void的意思不是将表达式强制转换为void类型的对象(void是一个没有对象的类型,或者说是一个空集),而是告诉编译器我们希望忽略表达式的值。其他相关样本: int main() { (void)(2+3); } 这个和另一个样本在语义上有什么区别吗 最后: int main() { void(); } 它不返回任何警告(这

我知道您可以取消“表达式无效”警告,使表达式无效:

int main()
{
    void(2+3);
}
如果我没有错的话,将某个对象强制转换为void的意思不是将表达式强制转换为
void
类型的对象(
void
是一个没有对象的类型,或者说是一个空集),而是告诉编译器我们希望忽略表达式的值。其他相关样本:

int main()
{
    (void)(2+3);
}
这个和另一个样本在语义上有什么区别吗

最后:

int main()
{
    void();
}

它不返回任何警告(这里是Coliru,充满了pedantic.related选项);但是,另一个会生成一个错误:

int main()
{
    (void)();
}

// Error:
//    main.cpp:6:9: error: expected primary-expression before 'void'
//       (void)();
//        ^
//    main.cpp:6:9: error: expected ')' before 'void'
void()
表达式的含义是什么?您是在创建类型为
void
,没有意义的临时对象,还是将空表达式强制转换为void

一般来说,我想了解有关void用法的完整情况,以及该标准规定的行为/语义。

void(2+3)
不是强制转换,而是伪构造函数。是的,
void(2+3)
(void)(2+3)
之间有语义上的区别
void(2+3)
是一种具有隐式类型转换的构造,如:
void((void)(2+3))
void()
也是一种合法的伪构造,不过它使用的是伪默认构造函数而不是伪复制构造函数

是的
void()
实质上是创建一个类型为
void
的临时对象(尽管正如您所说,实际上不能有void类型的对象,因此您永远不能对其执行任何操作;它不能作为参数传递,也不能指定给变量等)


强制转换操作表达式:
(void)(2+3)
操作表达式
(2+3)
。但是
()
不是一个合法的表达,所以
(void)(
是不合法的。类似地,您不能执行
static_cast()
static_cast(())

请注意,标准(至少不是C语言,不能确定C++)不需要此诊断;这只是编译器作者的帮助。因此,您在标准中找不到解决此问题的任何内容。@OliverCharlesworth,谢谢。我会用你的评论更新我的问题。“但是,另一个会产生错误”-问题中没有错误。如果姚提到一个错误,请也张贴它!事实上,
(void)unused_arg
是一种常用的方法,如果您仍然希望在其他位置显示有关特定函数中未使用参数的警告,则可以关闭该警告。例如,表示为
-Wunused value
要抑制此警告,请将未使用的表达式强制转换为“void”。
@Peregring lk伪构造函数支持复制构造语法。例如,
int(1)
。与常规复制构造函数一样,编译器隐式地执行从您传递的任何内容到复制构造函数的参数类型的转换。例如,
int(10.0)
10.0
double
隐式转换为
int
。伪构造函数
void(2+3)
也是如此:编译器向void插入隐式强制转换:
void((void)(2+3))
。当您使用语法
void()
时,它不使用伪复制构造函数,而是使用伪默认构造函数,因此没有隐式强制转换。我以前从未听说过“伪构造函数”这个术语。C++标准将此表达式称为“显式类型转换(函数表示法)”,并在[Exp.Type“简单类型说明符或typename说明符后跟括号中的表达式列表,根据表达式列表构造指定类型的值。如果表达式列表是单个表达式,则类型转换表达式与相应的强制转换表达式等效(在定义上,如果定义有意义)。“因此它是一个强制转换。@Peregring lk听起来不错,但关于默认构造函数的最后一部分并不是全部:形式为
T()
,创建一个prvalue(一个“临时”,但不一定是一个对象)这是值初始化。值初始化可以调用默认构造函数,但仅在某些情况下。即使对于类类型,如果默认构造函数很普通,也不会为值初始化调用它。@Peregring lk value initialized。不,不需要为值初始化传递值。正如dyp所说,
t()
生成一个prvalue,即使对于
void()
这样的对象也是如此,因此这是一个非对象“临时”的示例。@Peregring lk“Value initialization”只是一个名称;)零初始化不调用构造函数,因此
T()
无法正确构造复杂的类类型。但是,值初始化可以执行零初始化(例如,对于基本类型和具有普通默认构造函数的类类型)。