如果将void实际上定义为`struct void {} ;,则会破坏现有的C ++代码多少? [英] How much existing C++ code would break if void was actually defined as `struct void {};`

查看:112
本文介绍了如果将void实际上定义为`struct void {} ;,则会破坏现有的C ++代码多少?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

void是C ++类型系统中的一个怪异疣.这是一个不完整的类型,无法完成,它具有关于使用限制方式的各种魔术规则:

类型 cv void是不完整的类型,无法完成.这样的类型具有一组空值.它用作不返回值的函数的返回类型. 任何表达式都可以显式转换为 cv void([expr.cast])类型. 类型 cv void的表达式只能用作表达式语句,逗号表达式的操作数,?:的第二或第三操作数([expr.cond]),作为typeidnoexceptdecltype的操作数,作为return语句中返回类型为 cv void的函数的表达式或明确转换为 cv void类型.

(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上仍可以由编译器进行特殊处理.

除了兼容之外,这还可以提供:

  • 构造,复制和移动这些空对象,从而消除了模板中通常需要的特殊情况;
  • void *上的
  • 奖金指针算法,与char *相同,是常见的扩展,在处理二进制缓冲区时非常有用.

现在,除了<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 cv void ([expr.cast]). An expression of type cv void 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 of typeid, noexcept, or decltype, as the expression in a return statement for a function with the return type cv void, or as the operand of an explicit conversion to type cv void.

(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 for void and that "flowing off" of a void function is equivalent to return;);
  • 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 for char *, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆