If all of the members of std::tuple
are of standard layout types, is that std::tuple
itself standard layout? The presence of a user-defined copy-constr
One reason std::tuple
cannot be of standard layout, as any classes with members and base classes with members, is that the standard allows for space optimization when deriving even non-empty base classes. For example:
#include
#include
class X
{
uint64_t a;
uint32_t b;
};
class Y
{
uint16_t c;
};
class XY : public X, public Y
{
uint16_t d;
};
int main() {
printf("sizeof(X) is %zu\n", sizeof(X));
printf("sizeof(Y) is %zu\n", sizeof(Y));
printf("sizeof(XY) is %zu\n", sizeof(XY));
}
Outputs:
sizeof(X) is 16
sizeof(Y) is 2
sizeof(XY) is 16
The above shows that the standard allows for class trailing padding to be used for the derived class members. Class XY
has two extra uint16_t
members, yet its size equals to the size of base class X
.
In other words, class XY
layout is the same as that of another class that has no base classes and all the members of XY
ordered by address, e.g. struct XY2 { uint64_t a; uint32_t b; uint16_t c; uint16_t d; };
.
What makes it non-standard layout is that the size of a derived class is not a function of sizes of base classes and derived class members.
Note that the size of a struct
/class
is a multiple of the alignment of one of its members with the largest alignment requirement. So that an array of objects is suitably aligned for such a member. For built-in types normally sizeof(T) == alignof(T)
. Hence sizeof(X)
is a multiple of sizeof(uint64_t)
.
I am not sure whether the standard requires special treatment for struct
, but with g++-5.1.1
if class
is replaced with struct
the above code yields different output:
sizeof(X) is 16
sizeof(Y) is 2
sizeof(XY) is 24
In other words, the trailing padding space optimization is not used when struct
is involved (did not test for exact conditions).