- std::nullopt_t
- std::nullptr_t
- std::monostate
- std::tuple<>
And I'm sure there's more.
- std::nullopt_t
- std::nullptr_t
- std::monostate
- std::tuple<>
And I'm sure there's more.
As for the std::variant use case, using std::monostate is only a matter of convention there. You could use any of the other unit types just the same.
Using one type to represent empty literals for optional, tuple and pointer types, implicitly convertible to all of them, would make the compiler accept many obviously accidental constructs. In a world where the maintainers of C++ are trying their hardest to make the language safer what conceivable benefit would there be?
A function returning bottom cannot return, yet void foo() {} can. In fact it can even return the result of calling other void functions:
void bar() { }
void foo(){ return bar();}
In generic code void is usually internally replaced by a proper, regular void_t unit type and converted back to void at boundaries for backward compatibility. [[noreturn]] void bar();
would be a candidate for a bottom-returning function, except that [[noreturn]] isn't really part of the type system.I would almost rather argue that void is indeed the "bot" type, and a function marked with a void return type shouldn't be said to "return void;" rather we should say that it's an overloaded syntax that means the function has no return value at all. Same for "return bar()" there, that's just a false-friend of the syntax for returning a value, just syntactic sugar for "bar(); return;".
It's too late now. void pointers are used as a pun to mean "type wildcard." If void were a real thing that could have a size and address, that wouldn't work anymore.
Or you could say it the other way, that it is the bottom type, and the fact that it can be used as the unit type for returned values is a wart of the language. Furthermore, void* isn't a pointer of the unit type, it's a type for pointers to undefined/unspecified value types.
I think the original idea was that void meant "unknown", not "empty" or "non-existent": It was all about whether values could be allocated or not (the wart mentioned above). A plain void variable cannot, but a void pointer can be allocated. For functions, they just reused the keyword to mean "no return value" or "no arguments".
Hence, "void*" - a pointer to something, but it would be a syntax error to derefence this pointer.
Differently to other incomplete types void has some special behaviour: you can declare a function as returning void and return with no arguments is also special cased. You can also cast to void.
A void with proper unit semantics would simply be a complete type instead. The only special case would be return with no arguments implicitly returning a void instance, but that would be pure sugar.
C and C++ don't have a type spindle, where void would be at the bottom. Only C++ has the concept of subtype, only in the class system, and the C++ class system doesn't have a bottom type; there is no bottom class that is a base for all the others.
void is not a proper type; it's just a hack shoehorned into a convenient spot in the type system.
Which is why the C++ people have to invent this whole zoo of other things.
If void were a type, then, for starters, "return x;" would be syntactically valid in a function returning void. (Only, no possible x would satisfy the type system, so there would have to be a diagnosable rule violation in that regard.)
A function returning void does not return a type. It doesn't return anything; it is a procedure invoked for side effects.
The same situation could be achieved in other ways, like having a procedure keyword instead of void.
The (void) parameter list is another example of void just being a hack. It was introduced in ISO C, and then C++ adopted it for compatibility.
The 2023 draft of ISO C finally made () equivalent to (void), though it will probably take many decades for (void) to disappear.
A bottom type is not the base of all other types.
> void is not a proper type; it's just a hack shoehorned into a convenient spot in the type system.
It is a type, but it is not Regular and it is incomplete. 'return x;' is invalid in a void-returning function because it doesn't type check. 'return void()' or 'return (void)0;' or 'return void_returning_function();' are all valid because they type check.
Making void regular has been proposed multiple times [1]. It is a relatively simple extension but nobody that cares has the time to carry it through standardization.
[1] https://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0146r1...
6.8.7.5 The return statement
Constraints
1 A return statement with an expression shall not appear in a function whose return type is void.
It's a constraint violation. It doesn't matter what the type of the expression is.
It looks as if C++ made a small improvement here.
Yes, the bottom type is at the bottom of the type derivation hierarchy. That's why the word bottom is there; that's what it's at the bottom of. It's also why it can't have any instances. Since every other type is a supertype, then if the bottom type contained some value V, that value would be imposed into every other type! V would be a valid String, Widget, Integer, Stream, Array ... what have you.
But void is not the base of anything in C and C++.
You could argue that void is in some category of types where it is at the bottom; but no other types are in that category.
There is another problem: a bottom type should be the subtype of all types in that category. That includes being its own subtype. There we have a problem: C and C++ void is not a subtype of void in any sense.