Я хотел бы обобщить побитовые операторы в C ++, не думая, что базовая структура является массивом.
В качестве примера … если я хочу представить 86 бит, я бы использовал структуру структуры / класс, например:
typedef struct {
uint64_t x[1];
uint16_t y[1];
uint8_t z[1];
} sampleStruct;
Вместо этого, если бы я хотел выделить 160 бит, я бы использовал такую структуру:
typedef struct {
uint64_t x[2];
uint32_t y[1];
} sampleStruct;
Я предполагаю, что тривиальное, но не оптимальное решение для хранилища состоит в том, чтобы предположить, что все порции одинаковы и выделить минимум этих значений. он охватывает размер, который я внедряю, однако даже из-за физических упражнений я предпочитаю способ, которым я выставляюсь.
Для меня ясно, что я должен использовать метапрограммирование для решения проблемы, поэтому я должен правильно определить
template <int I>
typedef sampleStruct {
//something
}
Однако я не большой специалист по метапрограммированию шаблонов в C ++, поэтому я хотел бы понять, как лучше всего реализовать различный тип выборки структуры I. Я знаю, как выбрать наилучшее «покрытие» для моей длины. быть чем-то вроде:
N64 = I/64;
RemN = I%64;
if(0 < RemN <= 8) {
add uint8_t var;
} else if (8 < RemN <= 16) {
add uint16_t var;
} else if (16 < RemN <= 24) {
add uint16_t var;
add uint8_t var;
} else {
//Similarly handle the other cases from 24 < RemN < 64
}
Что я могу сделать, чтобы достичь того, что я хочу сделать?
Я также предполагаю, что правильное размещение фрагментов позволит достичь немного лучшей производительности по сравнению с другими возможными реализациями.
Надеюсь, это достаточно ясно …
(Предположим, C ++ 11 или более поздние версии).
Это возможно, но при этом достаточно много печатать. Проблема состоит в том, что C ++ не обеспечивает способ метапрограммического пропуска элемента данных (см., Например, Условное включение / исключение членов данных внутри шаблонов классов) поэтому вы должны специализироваться на его наличии или отсутствии:
template<int N64, bool P32, bool P16, bool P8>
struct sampleStructImpl;
template<int I>
using sampleStruct = sampleStructImpl<I/64, (I%64 >= 32), (I%32 >= 16), (I%16 >= 8)>;
Различные частичные специализации (всего 8) будут выглядеть следующим образом:
template<int N64>
struct sampleStructImpl<N64, true, true, true>
{
std::uint64_t x[N64];
std::uint32_t y;
std::uint16_t z;
std::uint8_t w;
};
template<int N64>
struct sampleStructImpl<N64, true, true, false>
{
std::uint64_t x[N64];
std::uint32_t y;
std::uint16_t z;
// omit std::uint8_t w;
};
// 6 more partial specializations...
Кроме того, поскольку массивы нулевой длины недопустимы, если вы хотите иметь возможность разрешать значения I
менее чем 64, вам придется специализироваться на N64
быть нулем:
template<>
struct sampleStructImpl<0, true, true, true>
{
// omit std::uint64_t x[0];
std::uint32_t y;
std::uint16_t z;
std::uint8_t w;
};
// 7 more specializations...
Было бы гораздо проще использовать std::array<std::uint8_t, (I + 7) / 8>
возможно с alignas
модификатор для 64-битного выравнивания.
Не было бы проще использовать только массив uint8_t
, например:
template <int I>
struct sampleStruct {
std::uint8_t v[(I % 8)? (I / 8) + 1 : (I / 8)];
};
Как вы упомянули, я предполагаю, что у вас нет доступа к отдельным членам x,y,z
(из вопроса не ясно, как бы вы получили доступ к базовым битам ..)
Можно также делать то, что вы хотите, но вы должны использовать наследование следующим образом:
template <int I>
struct largeBlock {
std::uint64_t x[I];
};
template <>
struct largeBlock<0> {
};
template <int I>
struct mediumBlock {
std::uint16_t y[I];
};
template <>
struct mediumBlock<0> {
};
template <int I>
struct smallBlock {
std::uint8_t z[(I / 8) + ((I % 8) ? 1 : 0) ];
};
template <>
struct smallBlock<0> {
};
template <int I>
struct sampleStruct : largeBlock<I / 64>, mediumBlock<(I % 64) / 16>, smallBlock<(I % 16)> {
};
Теперь ваши операции должны быть реализованы в терминах обращений к базовым объектам …