如果将void实际上定义为`struct void {} ;,则会破坏现有的C ++代码多少? [英] How much existing C++ code would break if void was actually defined as `struct void {};`
问题描述
void
是C ++类型系统中的一个怪异疣.这是一个不完整的类型,无法完成,它具有关于使用限制方式的各种魔术规则:
类型 cv
void
是不完整的类型,无法完成.这样的类型具有一组空值.它用作不返回值的函数的返回类型. 任何表达式都可以显式转换为 cvvoid
([expr.cast])类型. 类型 cvvoid
的表达式只能用作表达式语句,逗号表达式的操作数,?:
的第二或第三操作数([expr.cond]),作为typeid
,noexcept
或decltype
的操作数,作为return
语句中返回类型为 cvvoid
的函数的表达式或明确转换为 cvvoid
类型.
(N4778, [basic.fundamental]¶9)>
除了对所有这些奇怪规则感到不安之外,由于使用方法的局限性,在编写模板时,这常常是一个痛苦的特例.大多数情况下,我们希望它表现得更像 std::monostate
.
让我们想象一下,该标准而不是上面的报价,而是说void
之类的东西
这是一种类型,其定义等同于:
struct void { void()=default; template<typename T> explicit void(T &&) {}; // to allow cast to void };
在保持void *
魔法的同时-可以对任何对象进行别名,数据指针必须在通过void *
的往返过程中幸存下来.
此:
- 应涵盖
void
类型为"proper"的现有用例; - 可能可以消除通过标准传播的相当数量的垃圾-例如 [expr.cond]¶2可能是不需要的,并且 [stmt.return] 将被大大简化(同时仍保留
return
void
不允许使用任何表达式,并且void
函数的"flowing off"等效于return;
); - 仍然应该同样高效-如今,空类优化在任何地方都得到支持;
- 在现代ABI上本质上兼容,并且在较旧的ABI上仍可以由编译器进行特殊处理.
除了兼容之外,这还可以提供:
- 构造,复制和移动这些空对象,从而消除了模板中通常需要的特殊情况; 在
- 奖金指针算法,与
char *
相同,是常见的扩展,在处理二进制缓冲区时非常有用.
void *
上的现在,除了<type_traits>
东西的返回值可能发生更改之外,根据当前(C ++ 17)规则,格式正确的代码有什么可能中断?
对此有一个建议,它是奥卢2016年6月会议旅行报告:
Regular void,一个建议,删除语言中对void的大多数特殊情况的处理,使它的行为与其他任何类型一样.自从两个会议之前首次提出这个想法以来,这个想法得到了越来越多的支持,但是一些细节仍然存在争议,最显着的是删除void *类型的指针的能力.鼓励作者提出修改后的提案,也许还有一个实施方案可以帮助排除意外的麻烦.
我与作者聊天,他确认这基本上是在等待实施,一旦有实施,他计划将提案重新提出.
本文对哪些变化以及为什么进行了广泛的讨论,但实际上并没有引用它,但所解决的常见问题是:
- 此提案是否不会针对无效情况引入更多特殊情况?
- 为什么sizeof(void)等于0?
- 此中断std :: enable_if吗?
- 在实践中,这会破坏ABI兼容性吗?
- constexpr_if简化分支以简化void吗?
- 支持无效操作是不合逻辑的吗?
- 这不删除无结果"的概念吗?
- 这不是对空洞意义的改变吗?
void
is a bizarre wart in the C++ type system. It's an incomplete type that cannot be completed, and it has all sort of magic rules about the restricted ways it can be employed:
A type cv
void
is an incomplete type that cannot be completed; such a type has an empty set of values. It is used as the return type for functions that do not return a value. Any expression can be explicitly converted to type cvvoid
([expr.cast]). An expression of type cvvoid
shall be used only as an expression statement, as an operand of a comma expression, as a second or third operand of?:
([expr.cond]), as the operand oftypeid
,noexcept
, ordecltype
, as the expression in areturn
statement for a function with the return type cvvoid
, or as the operand of an explicit conversion to type cvvoid
.
(N4778, [basic.fundamental] ¶9)
Besides the itchy feeling about all those strange rules, due to the limited ways it can be used it often comes up as a painful special case when writing templates; most often it feels like we would like it to behave more like std::monostate
.
Let's imagine for a moment that instead of the quotation above, the standard said about void
something like
It's a type with definition equivalent to:
struct void { void()=default; template<typename T> explicit void(T &&) {}; // to allow cast to void };
while keeping the void *
magic - can alias any object, data pointers must survive the roundtrip through void *
.
This:
- should cover the existing use cases of the
void
type "proper"; - could probably allow the removal of a decent amount of junk about it spread through the standard - e.g. [expr.cond] ¶2 would probably be unneeded, and [stmt.return] would be greatly simplified (while still keeping the "exception" that
return
with no expression is allowed forvoid
and that "flowing off" of avoid
function is equivalent toreturn;
); - should still be just as efficient - empty class optimization is nowadays supported everywhere;
- be intrinsically compatible on modern ABIs, and could be still special-cased by the compiler on older ones.
Besides being compatible, this would provide:
- construction, copy and move of those empty objects, eliminating the special cases generally needed in templates;
- bonus pointer arithmetic on
void *
, operating as forchar *
, which is a common extension, quite useful when manipulating binary buffers.
Now, besides the possibly altered return values of <type_traits>
stuff, what could this possibly break in code that is well-formed according to current (C++17) rules?
There is a proposal for this, it is p0146: Regular Void
Presented below is a struct definition that is analogous to what is proposed for void in this paper. The actual definition is not a class type, but this serves as a fairly accurate approximation of what is proposed and how developers can think about void. What should be noticed is that this can be thought of as adding functionality to the existing void type, much like adding a special member function to any other existing type that didn't have it before, such as adding a move constructor to a previously non-copyable type. This comparison is not entirely analogous because void is currently no ordinary type, but it is a reasonable, informal description, with details covered later.
struct void { void() = default; void(const void&) = default; void& operator =(const void&) = default; template <class T> explicit constexpr void(T&&) noexcept {} }; constexpr bool operator ==(void, void) noexcept { return true; } constexpr bool operator !=(void, void) noexcept { return false; } constexpr bool operator <(void, void) noexcept { return false; } constexpr bool operator <=(void, void) noexcept { return true; } constexpr bool operator >=(void, void) noexcept { return true; } constexpr bool operator >(void, void) noexcept { return false; }
It was received well in Oulu June 2016 meeting Trip Report:
Regular void, a proposal to remove most instances of special-case treatment of void in the language, making it behave like any other type. The general idea enjoyed an increased level of support since its initial presentation two meetings ago, but some details were still contentious, most notably the ability to delete pointers of type void*. The author was encouraged to come back with a revised proposal, and perhaps an implementation to help rule out unexpected complications.
I chatted with the author and he confirmed that it is basically waiting for an implementation, once there is an implementation he plans on bringing the proposal back.
There is extensive discussion in the paper about what changes and why, it is not really quotable as a whole but the FAQ questions addressed are:
- Doesn't This Proposal Introduce More Special-Casing for void?
- Why Isn't sizeof(void) Equal to 0?
- Does This Break std::enable_if?
- In Practice, Would This Break ABI Compatibility?
- Doesn't constexpr_if Make Branching for void Easier?
- Isn't It Illogical to Support some-operation for void?
- Doesn't This Remove the Notion of "No Result?"
- Isn't This a Change to the Meaning of void?
这篇关于如果将void实际上定义为`struct void {} ;,则会破坏现有的C ++代码多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!