This is why C++ doesn't have ZSTs, it wants all objects to have identities, the obvious way to distinguish them is by where they are in memory, but ZSTs don't have distinct addresses in memory.
I'm not a C++ expert. Why does C++ want all objects to have identities? Presumably it has some feature or something Rust doesn't have that requires this?
It's pretty deeply tied into C++'s object lifetime mechanics, which rely on storage being available and reserved for the use of that object's lifetime. If multiple objects with valid lifetimes had a situation where one lifetime needs to end, what should happen to the other objects' lifetimes?
C++ actually did end up evolving the ability to define a zero-sized class without a unique memory address, but mostly to allow optimizations like the empty base optimization to apply in other situations where it could make sense, especially with templated or constexpr code.
C++ actually did end up evolving the ability to define a zero-sized class without a unique memory address
Did it? Are you talking about the no_unique_address attribute (I had to go look that up because WG21 apparently doesn't care about consistently using or not using separators in attribute names) ? That attribute lets you do the same trick as empty base class but without the ceremony, however it doesn't let you make ZSTs.
Yes, that's what I'm talking about. It does expand on the empty base object optimization, though it is still not fully generic.
But you can now have multiple zero-sized types as siblings in a struct or class that can be zero-sized, the restriction is that they do have to be different types.
But that's just not ZSTs. All C++ is doing is, as with EBC you can overlap a thing which doesn't need any representation with any number of other such things and with the no_unique_address attribute C++ will say their total size is 1.
C++ is bad at type arithmetic, that's nothing new. Rust has unit types like () which have size zero, and it has empty types like ! [aka never] which do not have a size because no values of these types exist. C++ struggles with this, if you attempt a unit type you get a type with a single byte that's all padding, thus size 1, and you can't write an empty type at all.
Comments
This is why C++ doesn't have ZSTs, it wants all objects to have identities, the obvious way to distinguish them is by where they are in memory, but ZSTs don't have distinct addresses in memory.
I'm not a C++ expert. Why does C++ want all objects to have identities? Presumably it has some feature or something Rust doesn't have that requires this?
It's pretty deeply tied into C++'s object lifetime mechanics, which rely on storage being available and reserved for the use of that object's lifetime. If multiple objects with valid lifetimes had a situation where one lifetime needs to end, what should happen to the other objects' lifetimes?
C++ actually did end up evolving the ability to define a zero-sized class without a unique memory address, but mostly to allow optimizations like the empty base optimization to apply in other situations where it could make sense, especially with templated or constexpr code.
Did it? Are you talking about the no_unique_address attribute (I had to go look that up because WG21 apparently doesn't care about consistently using or not using separators in attribute names) ? That attribute lets you do the same trick as empty base class but without the ceremony, however it doesn't let you make ZSTs.
Yes, that's what I'm talking about. It does expand on the empty base object optimization, though it is still not fully generic.
But you can now have multiple zero-sized types as siblings in a struct or class that can be zero-sized, the restriction is that they do have to be different types.
But that's just not ZSTs. All C++ is doing is, as with EBC you can overlap a thing which doesn't need any representation with any number of other such things and with the no_unique_address attribute C++ will say their total size is 1.
C++ is bad at type arithmetic, that's nothing new. Rust has unit types like () which have size zero, and it has empty types like ! [aka never] which do not have a size because no values of these types exist. C++ struggles with this, if you attempt a unit type you get a type with a single byte that's all padding, thus size 1, and you can't write an empty type at all.