这是这个问题的后续行动.
评价和在回答据说超过一次,更多的void{}是没有一个有效的类型-ID,也不是一个有效的表达式.
这很好,它是有道理的,这就是全部.
然后我通过工作草案的[7.1.7.4.1/2](占位符类型扣除).
有人说:
[...]
- 对于使用return包含占位符类型的返回类型声明的函数中发生的非丢弃 语句,T是声明的返回类型,并且e是return语句的操作数 .如果return语句没有操作数,那么e是void{};
[...]
那么,void{}(概念上)合法与否?
如果它在工作草案中提到是可接受的(尽管只是作为- 如果它是一个 -陈述),它必须是合法的.这意味着它也decltype(void{})应该是有效的,作为一个例子.
否则,工作草案应该使用void()而不是void{}?
嗯,说实话,我很确定我没有足够的技巧来指出工作草案中的错误,所以真正的问题是:我的推理出了什么问题?上面的子弹中提到了
什么void{},以及为什么在这种情况下它是一个法律表达?
我得到了一段void()用作参数的代码.代码不编译......很明显?
我们可以实例化任何类型的东西void吗?我相信答案是否定的,除了a void*.例如:
void askVoid(void param) {}错误:参数可能没有
void类型
void askNaught() {}并使用askNaught(void())`错误调用它:错误C2660 ::
takeNaught函数不带1个参数
template <typename T> void takeGeneric(T param) {}并调用它有takeGeneric(void())错误:错误C2893:无法专门化功能模板
void takeGeneric(T)
void voidType错误:不允许使用不完整的类型
auto autoVoid = void()错误:不能推断出
auto类型
void* voidPtr工作正常,但remove_pointer_t<decltype(voidPtr)> decltypeVoid错误:错误C2182 ::
decltypeVoid非法使用类型void
就是这样,对吧?void()C++中没有地方可供选择吗?这只是我给出的错误代码,对吧?
void在C++类型系统中是一个奇怪的疣.这是一个不完整的类型,无法完成,它有各种有关限制方式的魔术规则:
类型cv
void是不完整的类型,无法完成; 这种类型有一组空值.它用作不返回值的函数的返回类型.任何表达式都可以显式转换为cvvoid([expr.cast]).类型的表达式CVvoid应仅作为一个表达式语句,作为逗号表达式的操作数,作为一个第二或第三操作数?:([expr.cond]),作为操作数typeid,noexcept或decltype,如在表达return具有返回类型cv 的函数的语句void,或作为显式转换为cv 类型的操作数的语句void.
(N4778,[basic.fundamental]9)
除了对所有这些奇怪规则的痒感之外,由于它的使用方式有限,在编写模板时经常会出现一个痛苦的特殊情况; 通常情况下,我们希望它表现得更像std::monostate.
让我们想象一下,除了上面的引文,标准说的void是类似的东西
这是一个定义相当于以下类型的类型:
Run Code Online (Sandbox Code Playgroud)struct void { void()=default; template<typename T> explicit void(T &&) {}; // to allow cast to void };
保持void *魔法 - 可以别名任何对象,数据指针必须在往返过程中存活void *.
这个:
void"适当"类型的现有用例;return …c++ language-design generic-programming void language-lawyer
Nullable<T>像这样的语法糖有很多:
int? parsed to Nullable<int>
int? x = null
if (x != null) // Parsed to if (x.HasValue)
x = 56; // Parsed to x.Value = 56;
Run Code Online (Sandbox Code Playgroud)
和更多.
为什么if使用Nullable条件不起作用?
if (x)
{}
Run Code Online (Sandbox Code Playgroud)
它得到Complier错误,说无法转换Nullable<bool>为bool.
为什么它没有被解析if (x.HasValue && x.Value == true)或类似的东西?
这是最明显的用法 Nullable<bool>
由于出现错误,以下代码示例似乎使用 GCC 12.2 进行编译,与 Clang 15 和 MSVC 19.33 不同illegal initializer type 'void'。我预计代码会被所有三个编译器拒绝,因为构造(临时)void 对象没有意义。
auto f() { return void{}; }
using t = decltype(f());
Run Code Online (Sandbox Code Playgroud)
在示例中,函数f仅与未计算的操作数一起使用。f是否允许这样使用,或者甚至应该拒绝它的定义?(我知道void()创建纯右值的法律表达式,但这不属于本文的重点。)
标准中看似相关的段落:
不完全定义的对象类型和 cv void 是不完整类型 ([basic.fundamental])。
不完全定义的对象类型的实例的大小和布局是未知的。
如果我没记错的话,允许return void()在函数模板中编写以避免不必要的专业化和void类型重载。
同时,return void{}Clang 不识别类似的语法:
template<typename T>
T foo() { return T(); }
template<typename T>
T bar() { return T{}; }
int main() {
// ok everywhere
foo<void>();
// error in Clang
bar<void>();
}
Run Code Online (Sandbox Code Playgroud)
Clang 16 打印错误:
error: illegal initializer type 'void'
Run Code Online (Sandbox Code Playgroud)
在线演示: https: //gcc.godbolt.org/z/6o89reK3G
在cppreference中,我没有找到答案:对于非聚合类型T(), 和T{}应该表现相同。并且没有关于void类型的特殊注释。
这只是一个 Clang bug,还是相反,它是唯一严格遵循标准的编译器?