This is mostly trivia question, as I doubt that I will ever need this space saving.
While playing around on godbolt I noticed that both libstdc++ and libc++ implementations of std::variant
require more than 1 byte to store variant of empty structs.
libstc++ uses 2 bytes
libc++ uses 8 bytes
I presume it is just not worth the trouble to optimize this, but I wonder if there is any other reason. In particular is there something in standard wording for std::variant
that prevents this optimization.
Every object takes up at least 1 byte of space. The counter itself needs to take up at least 1 byte, but you also need space for the potential choices of object. Even if you use a union
, it still needs to be one byte. And it can't be the same byte as the counter.
Now, you might think that no_unique_address
could just come to the rescue, permitting the member union
to overlap with the counter if all of the union
elements are empty. But consider this code:
empty_type e{};
variant<empty_type> ve{in_place_index<0>}; //variant now stores the empty type.
auto *pve = ve.get_if<0>(); //Pointer to an `empty_type`.
memcpy(pve, &e, sizeof(empty_type)); //Copying from one trivial object to another.
The standard does not say that the members of a variant are "potentially-overlapping subojects" of variant
or any of its internal members. Therefore, it is 100% OK for a user to do a memcpy
from one trivial empty object to the other.
Which will overwrite the counter if it were overlapping with it. Therefore, it cannot be overlapping with it.