If I have an structure (e.g. employee
below), an array of such structure induces an strided array of members of the structure only if the size of the structure is a (least) common multiple (LCM) of the size all members.
Otherwise there will be pointers to specific members in the array that will not have integral pointer distances (measured in the size of the member class).
So, for example, given this structure:
struct employee{
std::string name;
short salary;
std::size_t age;
};
A std::vector<employee> v
(or an array employee[N]
for that matter) induces a strided array of salary
members (with stride sizeof(employee)/sizeof(short)
) and also a strided arrays of age
.
That is, an array of salaries is random accessed by &(v.data()->salary) + sizeof(employee)/sizeof(short)* n
.
However it doesn't induce a stride array of names, because sizeof(employee)
(=48) is not a multiple of sizeof(std::string)
(32) (in my system).
Of course, I could define the struct in this other way to allow this:
struct alignas(32) employee{ // or alignas(sizeof(std::string)) std::string name; short salary; std::size_t age; employee(short salary, std::size_t age) : salary{salary}, age{age}{} };
I am wondering if finding this proper alignas
argument is the only way to achieve this. Also, if there is an automatic way to obtain that number with out manually having to find the common multiple.
I seems that the most general way to do this, without reflection, is to do something like:
struct alignas(LCM(sizeof(std::string), sizeof(short), sizeof(std::size_t) ) employee{ std::string name; short salary; std::size_t age; employee(short salary, std::size_t age) : salary{salary}, age{age}{} };
That is, I have to enumerate all the members in advance. I could use constexpr std::lcm
by chaining it several times).
Is this the proper way to do it?
Also, one can always find pathological cases in which this doesn't even work because there are extra restrictions that the alignment needs to be a power of 2 (in some systems). In which case the common multiple needs to be also a power of 2 and can that be a huge number:
using password_type = std::array<char, 103>; // suppose I cannot change the 103
struct alignas(std::lcm(std::lcm(std::lcm(sizeof(std::string), sizeof(short)), sizeof(std::size_t)), sizeof(password_type))) employee{ // bad alignment
password_type password;
std::string name;
short salary;
std::size_t age;
employee(short salary, std::size_t age) : salary{salary}, age{age}{}
};
...error: requested alignment ‘3296’ is not a positive power of 2
For the alignment LCM to work I have to manually change the alignment of the specific member or add constexpr
ceiling to the nearest power of 2.
struct alignas(std::lcm(std::lcm(std::lcm(sizeof(std::string), sizeof(short)), sizeof(std::size_t)), 128)) employee{ // bad alignment
alignas(128) password_type password;
std::string name;
short salary;
std::size_t age;
employee(short salary, std::size_t age) : salary{salary}, age{age}{}
};
However that still doesn't solve the problem because alignas
is not part of the password_type
, it seems that the only solution then is to have a version of std::array
that also takes an internal alignment argument! std::aligned_array<char, 103, 128>
.
Ok, I still could do this, but at the cost of modifying other classes that where not coupled to employee
initially.
struct alignas(128) password_type : std::array<char, 103>{};
and it might end up working. But it is a lot of manual work, and it could change when I change the system, or add new members, etc.
Is there a more automatic way to do this? or some conventions to follow to make this problem less painful
Aucun commentaire:
Enregistrer un commentaire