std::array
is required by the standard to be well-defined even when the size is zero, so that std::array<T, 0>
is well-defined even though int[0]
is not allowed (though GCC implements an extension for it).
However, on GCC, Clang, and MSVC, std::array<T, 0>
is not treated as if it is a zero-sized struct, i.e. it does not act like it has trailing padding, and so [[no_unique_address]]
and the empty base optimization does not work with it. For example:
#include <array>
struct Tester {
[[no_unique_address]] std::array<char, 0> arr;
char c;
};
struct Tester2 : std::array<char, 0> {
char c;
};
// true on GCC, Clang, and MSVC at least:
static_assert(sizeof(Tester) == 2);
static_assert(sizeof(Tester2) == 2);
This is surprising, since it's obviously implementable as an empty struct. Is this something mandated by the standard?
Note: I've looked into the code for libstdc++, and it works like this because std::array<char, 0>
contains an instance of an empty struct that is not [[no_unique_address]]
and not using empty base class optimization, i.e. it looks something like this:
template <typename T>
struct array<T, 0> {
struct {} empty; // no [[no_unique_address]]!
};
But this doesn't doesn't explain why it was designed this way. Even though [[no_unique_address]]
wasn't a thing until C++20, the empty base class optimization is used liberally in other parts of the standard library, so it's definitely something that could be done if desired.
Aucun commentaire:
Enregistrer un commentaire