пятница, 6 сентября 2024 г.

[prog.c++] В склерозник: красивый кусок кода для подсчета смещения полей объекта и их выравнивания

В LinkedIn встретил ссылку на реализацию тупла без использования рекурсии: тыц. Реализация активно эксплуатирует C++ный fold expression и std::integer_sequence. Вот прям отличная демонстрация того, как эти фичи могут (и должны?) применяться.

Еще очень удачно совпало, что ссылка эта попала мне на глаза вскоре после того, как я проделал в чем-то похожую работу. Правда, у меня ситуация была чуть сложнее, ведь в тупле все N полей присутствуют всегда, поэтому размер всех туплов одного типа одинаков и фиксирован. Тогда как в моем случае объекты могут состоять из разного набора полей, поэтому нужно размер каждого объекта определять индивидуально, да и расположение полей в каждом объекте может быть уникальным. Так что в своей реализации без метапрограммирования на базе рекурсии я не смог обойтись. Возможно, еще и потому, что у меня мало опыта с fold expression и std::integer_sequence.

Поэтому решил утащить к себе в склерозник кусочек чужого кода на память. Чтобы легче было найти когда потребуется.

Этот кусочек кода отвечает за подсчет расположения полей внутри объекта с учетом их правильного выравнивания. В результате своей работы функция calculate_positions возвращает std::array размером (N+1), где элементы 0..(N-1) содержат смещение i-го поля, а элемент N -- общий размер объекта.

Оригинал кода можно увидеть здесь, а вот чуть-чуть модифицированная мной версия:

template <class T>
struct PositionWrapper {};

template <std::size_t _last, std::size_t... _is>
struct Positions
{
  static consteval auto to_array() {
    return std::array<std::size_tsizeof...(_is) + 1>{_is..., _last};      
  }
};

template <class T, std::size_t _last, std::size_t... _is>
consteval auto operator+(
  const Positions<_last, _is...>& /*_sizes*/,
  const PositionWrapper<T>& /*_w*/)
{
  if constexpr (_last % alignof(T) == 0) {
    constexpr auto last_new = _last + sizeof(T);
    return Positions<last_new, _is..., _last>{};
  } else {
    constexpr auto last_corrected = (_last / alignof(T) + 1) * alignof(T);
    constexpr auto last_new = last_corrected + sizeof(T);
    return Positions<last_new, _is..., last_corrected>{};
  }
}

template <class... Types>
consteval auto calculate_positions() {
  return (Positions<0>{} + ... + PositionWrapper<Types>{}).to_array();
}

2 комментария:

Andrey комментирует...

Евгений, дорогой! Прости что врываюсь из прошлого, видя твое (редкое) увлечение акустикой наушников, посоветуй закрытые наушники, которые играют ГРОМКО. Чтобы можно было слушать музыку громко когда все ушли спать, и не теребонькать бесконечно движок громкости, пытаясь сделать погромче. Ведь такая базовая потребность - сделать погромче, скажи КАК?

eao197 комментирует...

@Andrey

К сожалению, не могу подсказать :(
Мне подходят только вкладыши (и редкие модели внутриканальных затычек). В таких наушниках нет проблем с громкостью и с тем, что их звук мешает окружающим.
В телеграмме есть группа soundcheck39_chat, можно попробовать там спросить, там наверняка есть люди, через чьи руки прошло множество полноразмеров.