Веб-версияОткрыть в Telegram

ПостМапим значения на типы. Ч2

10 августа 2026
Г
Грокаем C++
Ссылка
нажмите — покажем
Мапим значения на типы. Ч2 #опытным Напомню проблему: enum class DataType: uint8_t { kInt32, kDouble, kUint64 }; template<typename T> T create_from_buffer(const void* buffer) { static_assert(std::is_trivially_copyable_v<T>, "Type T must be trivially copyable"); T obj; std::memcpy(&obj, buffer, sizeof(T)); return obj; } Как на основе DataType создать объект соответствующего типа? Compile-time мапа из массива, где по индексу подкапотного числа, стоящего за каждым перечислителем, позволяет получить соответствующий нужный тип и выбрать правильный обработчик. И все это за О(1) с тратами на сдвиг элемента в массиве Если же перечислителям явно присвоены числа, то этот номер не прокатит и надо думать дальше. Без шаблонной магии нам не обойтись, ведь мы хотим только добавлять маппинги, но не менять самого кода обработчиков и логику их выбора. И давайте заодно попробуем уйти от полной специализации шаблонов, как было в предыдущей части. Сделаем структуру аля ноду маппинга: template <DataType D, typename T> struct Node { static constexpr DataType key = D; using type = T; }; В структуре хранится конкретный перечислитель, получаемый из шаблонного параметра, и соответствующий ему тип. И в качестве пака шаблонных параметров нашей шаблонной функции мы будем передавать список нод Node<DataType::kInt32, int32_t>, Node<DataType::kDouble, double>, Node<DataType::kUint64, uint64_t>. В функции мы должны сделать примерно следующее. Перебираем рантайм значение enum'а на соответствие значению Key из нод пака параметров. Перебираем, пока не найдем нужный и после используем правильную ноду для получения замаппленого типа. И вот этот перебор можно делать через fold expression и короткозамкнутый оператор ||. Как только условие истинно, вычисления прекращаются. template <typename... Es> DataVariant ConvertImpl(const void* buffer, DataType type) { DataVariant result; bool found = ((Es::key == type ? (result = create_from_buffer<typename Es::type>(buffer), true) : false) || ...); if (!found) throw std::runtime_error("Unknown type"); return result; } DataVariant Convert(const void* buffer, DataType type) { return ConvertImpl< Node<DataType::kInt32, int32_t>, Node<DataType::kDouble, double>, Node<DataType::kUint64, uint64_t> >(buffer, type); } Также тут используется фишка оператора запятой, что результатом выражения является только самый крайний справа операнд. Теперь вместо поиска элемента в массиве по индексу мы занимаемся линейным проходом выполнения логического ИЛИ для типов. На первый взгляд это может быть сильно дольше, но компиляторы хорошо умеют оптимизировать fold expression, даже в худшем случае большой разницы не будет. Код кстати по размеру уже не сильно больше изначального свитча. Вот примерчик с рабочим кодом, можете поиграться. Use tricks. Stay cool. #template #cpp17
18 · 3.7K ·

Рядом в ленте

ГГрокаем C++​​Ответ #опытным 2 вещи нужно знать(помимо всего остального С++😆), чтобы правильно ответить на квиз выше: 1️⃣ Сокрытие имен Когда в классе объявляют метод с некГГрокаем C++Мапим значения на типы. Ч1 #опытным Иногда требуется на основе какого-то рантайм значения, например перечисления, получить какой-то соответствующий тип. Наприме
это сообщение
ГГрокаем C++​​std::inplace_vector #опытным Стандартная библиотека традиционно запаздывает с внедрением полезного функционала. Вот у нас есть std::vector. Прекрасный контейнГГрокаем C++​​Гибридные вектора #опытным std::inplace_vector воплощает в себя преимущества динамического расширения размеров и отсутствия аллокаций. Полезная штука, но и он

Открытая публичная лента из поискового индекса ChatCrawler — «Google по публичному Telegram»; обновляется по мере обхода площадки. Время — UTC.

Только публичный контент, официальный API Telegram. О проекте · Вопросы · Чего мы не делаем · Убрать страницу из выдачи · Каталог · Поиск · Как мы считаем