I have the following class,
struct employee {
std::string name;
short salary;
std::size_t age;
};
Just as an example, in Linux amd64, the size of the struct is 48 bytes, and the size of std::string is 32, that is, not a multiple.
Now, I need, in a cross-platform way, for employee to have a size that is a multiple of the size of std::string (first member).
(Cross-platform could mean, for example, both Linux amd64 and Apple ARM.)
That is, sizeof(employee) % sizeof(std::string) == 0.
I tried controlling the padding using alignas for the whole class or the members, but the requirement to be a power of 2 is too restrictive, it seems.
Then I tried to add a char array at the end.
Still, I had two problems, first, what is the exact size of the array in different platforms at compile-time, and second not adding another member that can screw up the nice aggregate initialization of the class.
For the first, I do this:
struct employee_dummy {
std::string name;
short salary;
std::size_t age;
};
struct employee {
std::string name;
short salary;
std::size_t age;
char padding[(sizeof(employee_dummy)/sizeof(std::string)+1)*sizeof(std::string) - sizeof(employee_dummy)];
};
Note the ugly dummy class, and I don't even know if the logic is correct.
For the second problem, I don't have a solution. I could do this, but then I would need to add a constructor, the class would not be an aggregate, etc.
struct employee {
std::string name;
short salary;
std::size_t age;
private:
char padding[(sizeof(employee_dummy)/sizeof(std::string)+1)*sizeof(std::string) - sizeof(employee_dummy)];
};
How can I control the size of the struct with standard or non-standard mechanisms and keep the class as an aggregate?
Here is a link to play with this problem empirically: https://cppinsights.io/s/f2fb5239
NOTE ADDED:
I realized that, if the technique to add padding is correct, the calculation is even more difficult because the dummy class might be already adding padding, so I have to take into account the offset of the last element instead.
In this example I want data to be a multiple of the first member (std::complex):
struct dummy {
std::complex<double> a;
double b;
std::int64_t b2;
int c;
};
struct data {
std::complex<double> a;
double b;
std::int64_t b2;
int c;
char padding[ ((offsetof(dummy, c) + sizeof(c)) / sizeof(std::complex<double>) + 1)* sizeof(std::complex<double>) - (offsetof(dummy, c) + sizeof(c)) ];
};
Note the formula is even worse now.
Here is a standard-compliant, no ifs or buts, version.
Use it like this:
Now
stridedhas a size that is a multiple of 47 (and of course is aligned correctly). On my computer it is 376.You can make
employeea template in this fashion:or make it a member of a template (instead of
double x):and then use
employee_wrapperas a vector element. But provide a specialization for 0 either way.You can try using
std::arrayinstead of a C-style array and avoid providing a specialization for 0, but it may or may not get optimized out when the size is 0.[[no_unique_address]](C++20) may help here.Note, something like
adjust_padding<need_strided, 117>::typemay overflow the default constexpr depth of your compiler.