Если у меня есть структура (например, employee
ниже), массив такой структуры индуцирует пошаговые массивы всех членов структуры, только если размер структуры является (наименьшим) общим кратным (LCM) Размер всех членов.
В противном случае в массиве будут указатели на конкретные экземпляры элементов, у которых не будет целых расстояний указателей (измеренных в размере класса элемента).
Так, например, с учетом этой структуры:
struct employee{
std::string name;
short salary;
std::size_t age;
};
A std::vector<employee> v
(или массив employee[N]
в этом отношении) индуцирует расширенный массив salary
членов (с шагом sizeof(employee)/sizeof(short)
), а также расширенные массивы age
.
То есть, массив зарплат выбирается случайным образом &(v.data()->salary) + sizeof(employee)/sizeof(short)* n
.
Однако это не вызывает большого количества имен, потому что sizeof(employee)
(= 48) не кратно sizeof(std::string)
(32) (в моей системе).
Конечно, я мог бы определить структуру другим способом, чтобы разрешить это:
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}{}
};
Мне интересно, единственный ли способ добиться этого - найти этот правильный аргумент alignas
. Кроме того, если есть автоматический способ получить это число без необходимости вручную находить общий множитель.
Мне кажется, что самый общий способ сделать это, не задумываясь, это сделать что-то вроде:
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}{}
};
То есть я должен заранее перечислить всех членов.
Я мог бы использовать constexpr std::lcm
, связав его несколько раз).
Это правильный способ сделать это?
Кроме того, всегда можно найти патологические случаи, в которых это даже не работает, потому что есть дополнительные ограничения, что выравнивание должно быть степенью 2 (в некоторых системах). В этом случае общее кратное число также должно быть степенью 2 и может быть огромным:
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
Для выравнивания LCM необходимо вручную изменить выравнивание конкретного элемента или добавить потолок constexpr
до ближайшей степени 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}{}
};
Однако это все еще не решает проблему, потому что alignas
не является частью password_type
, кажется, что единственное решение - это иметь версию std::array
, которая также принимает внутренний аргумент выравнивания! std::aligned_array<char, 103, 128>
.
Хорошо, я все еще мог сделать это, но за счет изменения других классов, которые изначально не были связаны с employee
.
struct alignas(128) password_type : std::array<char, 103>{};
и это может сработать. Но это много ручной работы, и она может измениться, когда я изменю систему, добавлю новых участников и т. Д.
Есть ли более автоматический способ сделать это? или некоторые соглашения, которым нужно следовать, чтобы сделать эту проблему менее болезненной