How much existing C++ code would break if void was actually defined as `struct void {};`
up vote
15
down vote
favorite
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?
c++ language-lawyer void language-design generic-programming
|
show 2 more comments
up vote
15
down vote
favorite
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?
c++ language-lawyer void language-design generic-programming
4
Have you heard about Regular Void?
– Rakete1111
Nov 7 at 20:31
1
@Rakete1111: agh this did seem like an obvious solution! Thank you, I'll look into it!
– Matteo Italia
Nov 7 at 20:32
2
@Rakete1111 Arrays ofvoid
look like a killer feature.
– VTT
Nov 7 at 20:43
The standard requires thatsizeof(void*) == sizeof(char*)
. The fact that pointers to incomplete types are a thing means that all struct pointers "smell the same". Since you are proposing thatvoid
be a struct, this means thatsizeof(void*) == sizeof(struct Foo*)
, which means thatsizeof(char*) == sizeof(struct Foo*)
, which makes life difficult for non-byte-addressable systems like TOPS-20.
– Raymond Chen
Nov 10 at 4:52
@RaymondChen: is the problem you are highlighting that, given thatsizeof(void *) >= sizeof(any other data object)
, it would makestruct
pointers too big for no good reason?
– Matteo Italia
Nov 10 at 10:55
|
show 2 more comments
up vote
15
down vote
favorite
up vote
15
down vote
favorite
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?
c++ language-lawyer void language-design generic-programming
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?
c++ language-lawyer void language-design generic-programming
c++ language-lawyer void language-design generic-programming
edited Nov 10 at 4:03
curiousguy
4,50622940
4,50622940
asked Nov 7 at 20:29
Matteo Italia
96.9k13135236
96.9k13135236
4
Have you heard about Regular Void?
– Rakete1111
Nov 7 at 20:31
1
@Rakete1111: agh this did seem like an obvious solution! Thank you, I'll look into it!
– Matteo Italia
Nov 7 at 20:32
2
@Rakete1111 Arrays ofvoid
look like a killer feature.
– VTT
Nov 7 at 20:43
The standard requires thatsizeof(void*) == sizeof(char*)
. The fact that pointers to incomplete types are a thing means that all struct pointers "smell the same". Since you are proposing thatvoid
be a struct, this means thatsizeof(void*) == sizeof(struct Foo*)
, which means thatsizeof(char*) == sizeof(struct Foo*)
, which makes life difficult for non-byte-addressable systems like TOPS-20.
– Raymond Chen
Nov 10 at 4:52
@RaymondChen: is the problem you are highlighting that, given thatsizeof(void *) >= sizeof(any other data object)
, it would makestruct
pointers too big for no good reason?
– Matteo Italia
Nov 10 at 10:55
|
show 2 more comments
4
Have you heard about Regular Void?
– Rakete1111
Nov 7 at 20:31
1
@Rakete1111: agh this did seem like an obvious solution! Thank you, I'll look into it!
– Matteo Italia
Nov 7 at 20:32
2
@Rakete1111 Arrays ofvoid
look like a killer feature.
– VTT
Nov 7 at 20:43
The standard requires thatsizeof(void*) == sizeof(char*)
. The fact that pointers to incomplete types are a thing means that all struct pointers "smell the same". Since you are proposing thatvoid
be a struct, this means thatsizeof(void*) == sizeof(struct Foo*)
, which means thatsizeof(char*) == sizeof(struct Foo*)
, which makes life difficult for non-byte-addressable systems like TOPS-20.
– Raymond Chen
Nov 10 at 4:52
@RaymondChen: is the problem you are highlighting that, given thatsizeof(void *) >= sizeof(any other data object)
, it would makestruct
pointers too big for no good reason?
– Matteo Italia
Nov 10 at 10:55
4
4
Have you heard about Regular Void?
– Rakete1111
Nov 7 at 20:31
Have you heard about Regular Void?
– Rakete1111
Nov 7 at 20:31
1
1
@Rakete1111: agh this did seem like an obvious solution! Thank you, I'll look into it!
– Matteo Italia
Nov 7 at 20:32
@Rakete1111: agh this did seem like an obvious solution! Thank you, I'll look into it!
– Matteo Italia
Nov 7 at 20:32
2
2
@Rakete1111 Arrays of
void
look like a killer feature.– VTT
Nov 7 at 20:43
@Rakete1111 Arrays of
void
look like a killer feature.– VTT
Nov 7 at 20:43
The standard requires that
sizeof(void*) == sizeof(char*)
. The fact that pointers to incomplete types are a thing means that all struct pointers "smell the same". Since you are proposing that void
be a struct, this means that sizeof(void*) == sizeof(struct Foo*)
, which means that sizeof(char*) == sizeof(struct Foo*)
, which makes life difficult for non-byte-addressable systems like TOPS-20.– Raymond Chen
Nov 10 at 4:52
The standard requires that
sizeof(void*) == sizeof(char*)
. The fact that pointers to incomplete types are a thing means that all struct pointers "smell the same". Since you are proposing that void
be a struct, this means that sizeof(void*) == sizeof(struct Foo*)
, which means that sizeof(char*) == sizeof(struct Foo*)
, which makes life difficult for non-byte-addressable systems like TOPS-20.– Raymond Chen
Nov 10 at 4:52
@RaymondChen: is the problem you are highlighting that, given that
sizeof(void *) >= sizeof(any other data object)
, it would make struct
pointers too big for no good reason?– Matteo Italia
Nov 10 at 10:55
@RaymondChen: is the problem you are highlighting that, given that
sizeof(void *) >= sizeof(any other data object)
, it would make struct
pointers too big for no good reason?– Matteo Italia
Nov 10 at 10:55
|
show 2 more comments
1 Answer
1
active
oldest
votes
up vote
9
down vote
accepted
There is a proposal for this, 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?
3
It would be harder to differentiate between a pointer to something unknown (type-erasure the ultimate) and avoid
-object / array ofvoid
s. I wonder how implicit conversion of data-pointer tovoid*
will fare. Sometimes, the lack of regularity is actually a safety-feature.
– Deduplicator
Nov 7 at 21:07
Isvoid
the base class of every other class? And of every scalar type? Bonus Q: Isvoid
a virtual base (to avoid ambiguous conversions)? Trying to fit a complete consistent framework (or type system) over the inconsistency of a bunch of ad hoc rules is hard.
– curiousguy
Nov 10 at 7:20
@curiousguy: read the proposal: it's essentially what I outlined in the question;void
becomes a regular, instantiable type; current special rules aboutvoid *
remain; base classes and such never come into play.
– Matteo Italia
Nov 10 at 11:10
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
9
down vote
accepted
There is a proposal for this, 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?
3
It would be harder to differentiate between a pointer to something unknown (type-erasure the ultimate) and avoid
-object / array ofvoid
s. I wonder how implicit conversion of data-pointer tovoid*
will fare. Sometimes, the lack of regularity is actually a safety-feature.
– Deduplicator
Nov 7 at 21:07
Isvoid
the base class of every other class? And of every scalar type? Bonus Q: Isvoid
a virtual base (to avoid ambiguous conversions)? Trying to fit a complete consistent framework (or type system) over the inconsistency of a bunch of ad hoc rules is hard.
– curiousguy
Nov 10 at 7:20
@curiousguy: read the proposal: it's essentially what I outlined in the question;void
becomes a regular, instantiable type; current special rules aboutvoid *
remain; base classes and such never come into play.
– Matteo Italia
Nov 10 at 11:10
add a comment |
up vote
9
down vote
accepted
There is a proposal for this, 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?
3
It would be harder to differentiate between a pointer to something unknown (type-erasure the ultimate) and avoid
-object / array ofvoid
s. I wonder how implicit conversion of data-pointer tovoid*
will fare. Sometimes, the lack of regularity is actually a safety-feature.
– Deduplicator
Nov 7 at 21:07
Isvoid
the base class of every other class? And of every scalar type? Bonus Q: Isvoid
a virtual base (to avoid ambiguous conversions)? Trying to fit a complete consistent framework (or type system) over the inconsistency of a bunch of ad hoc rules is hard.
– curiousguy
Nov 10 at 7:20
@curiousguy: read the proposal: it's essentially what I outlined in the question;void
becomes a regular, instantiable type; current special rules aboutvoid *
remain; base classes and such never come into play.
– Matteo Italia
Nov 10 at 11:10
add a comment |
up vote
9
down vote
accepted
up vote
9
down vote
accepted
There is a proposal for this, 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?
There is a proposal for this, 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?
edited Nov 8 at 14:06
answered Nov 7 at 20:56
Shafik Yaghmour
123k23309512
123k23309512
3
It would be harder to differentiate between a pointer to something unknown (type-erasure the ultimate) and avoid
-object / array ofvoid
s. I wonder how implicit conversion of data-pointer tovoid*
will fare. Sometimes, the lack of regularity is actually a safety-feature.
– Deduplicator
Nov 7 at 21:07
Isvoid
the base class of every other class? And of every scalar type? Bonus Q: Isvoid
a virtual base (to avoid ambiguous conversions)? Trying to fit a complete consistent framework (or type system) over the inconsistency of a bunch of ad hoc rules is hard.
– curiousguy
Nov 10 at 7:20
@curiousguy: read the proposal: it's essentially what I outlined in the question;void
becomes a regular, instantiable type; current special rules aboutvoid *
remain; base classes and such never come into play.
– Matteo Italia
Nov 10 at 11:10
add a comment |
3
It would be harder to differentiate between a pointer to something unknown (type-erasure the ultimate) and avoid
-object / array ofvoid
s. I wonder how implicit conversion of data-pointer tovoid*
will fare. Sometimes, the lack of regularity is actually a safety-feature.
– Deduplicator
Nov 7 at 21:07
Isvoid
the base class of every other class? And of every scalar type? Bonus Q: Isvoid
a virtual base (to avoid ambiguous conversions)? Trying to fit a complete consistent framework (or type system) over the inconsistency of a bunch of ad hoc rules is hard.
– curiousguy
Nov 10 at 7:20
@curiousguy: read the proposal: it's essentially what I outlined in the question;void
becomes a regular, instantiable type; current special rules aboutvoid *
remain; base classes and such never come into play.
– Matteo Italia
Nov 10 at 11:10
3
3
It would be harder to differentiate between a pointer to something unknown (type-erasure the ultimate) and a
void
-object / array of void
s. I wonder how implicit conversion of data-pointer to void*
will fare. Sometimes, the lack of regularity is actually a safety-feature.– Deduplicator
Nov 7 at 21:07
It would be harder to differentiate between a pointer to something unknown (type-erasure the ultimate) and a
void
-object / array of void
s. I wonder how implicit conversion of data-pointer to void*
will fare. Sometimes, the lack of regularity is actually a safety-feature.– Deduplicator
Nov 7 at 21:07
Is
void
the base class of every other class? And of every scalar type? Bonus Q: Is void
a virtual base (to avoid ambiguous conversions)? Trying to fit a complete consistent framework (or type system) over the inconsistency of a bunch of ad hoc rules is hard.– curiousguy
Nov 10 at 7:20
Is
void
the base class of every other class? And of every scalar type? Bonus Q: Is void
a virtual base (to avoid ambiguous conversions)? Trying to fit a complete consistent framework (or type system) over the inconsistency of a bunch of ad hoc rules is hard.– curiousguy
Nov 10 at 7:20
@curiousguy: read the proposal: it's essentially what I outlined in the question;
void
becomes a regular, instantiable type; current special rules about void *
remain; base classes and such never come into play.– Matteo Italia
Nov 10 at 11:10
@curiousguy: read the proposal: it's essentially what I outlined in the question;
void
becomes a regular, instantiable type; current special rules about void *
remain; base classes and such never come into play.– Matteo Italia
Nov 10 at 11:10
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53197340%2fhow-much-existing-c-code-would-break-if-void-was-actually-defined-as-struct-v%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
4
Have you heard about Regular Void?
– Rakete1111
Nov 7 at 20:31
1
@Rakete1111: agh this did seem like an obvious solution! Thank you, I'll look into it!
– Matteo Italia
Nov 7 at 20:32
2
@Rakete1111 Arrays of
void
look like a killer feature.– VTT
Nov 7 at 20:43
The standard requires that
sizeof(void*) == sizeof(char*)
. The fact that pointers to incomplete types are a thing means that all struct pointers "smell the same". Since you are proposing thatvoid
be a struct, this means thatsizeof(void*) == sizeof(struct Foo*)
, which means thatsizeof(char*) == sizeof(struct Foo*)
, which makes life difficult for non-byte-addressable systems like TOPS-20.– Raymond Chen
Nov 10 at 4:52
@RaymondChen: is the problem you are highlighting that, given that
sizeof(void *) >= sizeof(any other data object)
, it would makestruct
pointers too big for no good reason?– Matteo Italia
Nov 10 at 10:55