Date: Mon, 22 Jul 2024 16:52:18 +0200
On 21/07/2024 18:51, Frederick Virchanza Gotham via Std-Proposals wrote:
> Typically when implementing a class such as 'std::optional', the size
> of 'std::optional<T>' is equal to "sizeof(T) + 1u", because one more
> byte is needed to store a boolean to indicate whether there is a valid
> object in existence.
>
> We can use "__datasizeof" or "[[no_unique_address]]" in order to try
> use the tail padding of T to store the boolean, and if we succeed,
> then sizeof(optional<T>) == sizeof(T).
So the first paragraph says something (size is sizeof(T)+1) which is
directly contradicted by the second paragraph (size is sizeof(T)). Which
one is true?
>
> If T has no tail padding, then we need an extra byte to store the
> boolean. Unless . . . we had the ability to mark the class
> 'null_bytes==null_object" as follows:
>
> class T (null_bytes==null_object) {
> . . .
> };
>
> Marking a class as 'null_bytes==null_object' means that a byte-pattern
> of all zeroes is a 'null object'.
> So then "std::optional::has_value" could be:
>
> bool optional::has_value(void) noexcept requires
> is_null_bytes_null_object_v<T>
> {
> return (0u == *storage) && !memcmp(storage, storage + 1u,
> sizeof(storage) - 1u);
> }
Being a "null object" (whatever that means) doesn't mean that such a
null object can be used as the representation of a non-engaged optional.
A non-engaged optional means there's NO object. A null object means that
there is an object. This is a complete non-sequitur.
This doesn't mean one can't, in principle, use some bits of an object's
representation in order to encode the engaged/disengaged status. See:
> https://youtu.be/MWBfmmg8-Yo?t=2468
My 2 c,
--
Giuseppe D'Angelo
> Typically when implementing a class such as 'std::optional', the size
> of 'std::optional<T>' is equal to "sizeof(T) + 1u", because one more
> byte is needed to store a boolean to indicate whether there is a valid
> object in existence.
>
> We can use "__datasizeof" or "[[no_unique_address]]" in order to try
> use the tail padding of T to store the boolean, and if we succeed,
> then sizeof(optional<T>) == sizeof(T).
So the first paragraph says something (size is sizeof(T)+1) which is
directly contradicted by the second paragraph (size is sizeof(T)). Which
one is true?
>
> If T has no tail padding, then we need an extra byte to store the
> boolean. Unless . . . we had the ability to mark the class
> 'null_bytes==null_object" as follows:
>
> class T (null_bytes==null_object) {
> . . .
> };
>
> Marking a class as 'null_bytes==null_object' means that a byte-pattern
> of all zeroes is a 'null object'.
> So then "std::optional::has_value" could be:
>
> bool optional::has_value(void) noexcept requires
> is_null_bytes_null_object_v<T>
> {
> return (0u == *storage) && !memcmp(storage, storage + 1u,
> sizeof(storage) - 1u);
> }
Being a "null object" (whatever that means) doesn't mean that such a
null object can be used as the representation of a non-engaged optional.
A non-engaged optional means there's NO object. A null object means that
there is an object. This is a complete non-sequitur.
This doesn't mean one can't, in principle, use some bits of an object's
representation in order to encode the engaged/disengaged status. See:
> https://youtu.be/MWBfmmg8-Yo?t=2468
My 2 c,
--
Giuseppe D'Angelo
Received on 2024-07-22 14:52:26