TGStat
TGStat
Qidiruv uchun matnni kiriting
Ilg‘or kanal qidiruvi
  • flag Uzbek
    Sayt tili
    flag Russian flag English flag Uzbek
  • Saytga kirish
  • Katalog
    Kanal va guruhlar katalogi Hududiy to‘plamlar Tematik to‘plamlar Платные каналы Kanallar qidiruvi
    Kanal/guruh qo‘shish
  • Reytinglar
    Kanallar reytingi Guruhlar reytingi Postlar reytingi
    Brendlar va shaxslar reytingi
  • Analitika
  • Postlarda qidiruv
  • Telegram'ni kuzatish
  • Targ‘ibot
    Yandex Business orqali reklama Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
Грокаем C++

10 Aug, 13:00

Telegram'da ochish Ulashish Shikoyat qilish

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

Напомню проблему:

enum class DataType: uint8_t {
kInt32,
kDouble,
kUint64
};

template
T create_from_buffer(const void* buffer) {
static_assert(std::is_trivially_copyable_v,
"Type T must be trivially copyable");

T obj;
std::memcpy(&obj, buffer, sizeof(T));
return obj;
}

Как на основе DataType создать объект соответствующего типа?

Compile-time мапа из массива, где по индексу подкапотного числа, стоящего за каждым перечислителем, позволяет получить соответствующий нужный тип и выбрать правильный обработчик. И все это за О(1) с тратами на сдвиг элемента в массиве

Если же перечислителям явно присвоены числа, то этот номер не прокатит и надо думать дальше.

Без шаблонной магии нам не обойтись, ведь мы хотим только добавлять маппинги, но не менять самого кода обработчиков и логику их выбора.

И давайте заодно попробуем уйти от полной специализации шаблонов, как было в предыдущей части.

Сделаем структуру аля ноду маппинга:

template
struct Node { static constexpr DataType key = D; using type = T; };

В структуре хранится конкретный перечислитель, получаемый из шаблонного параметра, и соответствующий ему тип.

И в качестве пака шаблонных параметров нашей шаблонной функции мы будем передавать список нод Node, Node, Node.

В функции мы должны сделать примерно следующее. Перебираем рантайм значение enum'а на соответствие значению Key из нод пака параметров. Перебираем, пока не найдем нужный и после используем правильную ноду для получения замаппленого типа.

И вот этот перебор можно делать через fold expression и короткозамкнутый оператор ||. Как только условие истинно, вычисления прекращаются.

template
DataVariant ConvertImpl(const void* buffer, DataType type) {
DataVariant result;
bool found = ((Es::key == type
? (result = create_from_buffer(buffer), true)
: false) || ...);
if (!found) throw std::runtime_error("Unknown type");
return result;
}

DataVariant Convert(const void* buffer, DataType type) {
return ConvertImpl<
Node,
Node,
Node
>(buffer, type);
}

Также тут используется фишка оператора запятой, что результатом выражения является только самый крайний справа операнд.

Теперь вместо поиска элемента в массиве по индексу мы занимаемся линейным проходом выполнения логического ИЛИ для типов.

На первый взгляд это может быть сильно дольше, но компиляторы хорошо умеют оптимизировать fold expression, даже в худшем случае большой разницы не будет.

Код кстати по размеру уже не сильно больше изначального свитча.

Вот примерчик с рабочим кодом, можете поиграться.

Use tricks. Stay cool.

#template #cpp17

2.8k 0 18 9 27
Katalog
Kanal va guruhlar katalogi Kanallar to‘plamlari Kanallar qidiruvi Kanal/guruh qo‘shish
Reytinglar
Telegram-kanallar reytingi Telegram-guruhlar reytingi Postlar reytingi Brendlar va shaxslar reytingi
API
Statistika API'si Postlar qidiruvi API'si API Callback
Kanallarimiz
@TGStat @TGStat_Chat @telepulse @TGStatAPI
O‘qish
Академия TGStat Telegram tadqiqoti 2019 Telegram tadqiqoti 2021 Telegram tadqiqoti 2023
Kontaktlar
Справочный центр Qo‘llab-quvvatlash Email Vakansiyalar
Har xil narsalar
Foydalanuvchi shartnomasi Maxfiylik siyosati Ommaviy oferta
Botlarimiz
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot