Случай переключения, сгенерированный во время компиляции, без снижения производительностиC++

Программы на C++. Форум разработчиков
Ответить Пред. темаСлед. тема
Anonymous
 Случай переключения, сгенерированный во время компиляции, без снижения производительности

Сообщение Anonymous »

Я пытаюсь провести рефакторинг большого количества кода в проекте, над которым работаю, и мои коллеги являются поклонниками копирования и вставки. Вы можете найти такие функции диспетчеризации, разбросанные по множеству классов:

Код: Выделить всё

void dispatch(const Buffer& buffer)
{
switch (buffer.getId())
{
case Id::Type1:
{
Type1 obj;
obj.deserialize(Buffer);
// ... other code to print and process the buffer
}
break;
case Id::Type2:
{
Type2 obj;
obj.deserialize(Buffer);
// ... same code to print and process the buffer as above
}
break;
// ... and again, and again... for 10 to 30 types, depending on context
}
Несколько ограничений для этой проблемы:
  • мы не можем контролировать Type1, Type2... поэтому мы не можем играть с их иерархией или интерфейсами. В некотором контексте эти типы наследуются от общего базового класса (слишком общего, чтобы быть полезным), но вы можете эффективно рассматривать их как несвязанные типы в рамках этой проблемы.
  • код выполнение в каждом случае фактически одинаково, если вы видите все, что связано с типами, как данные, к которым вы можете получить доступ через идентификатор.
  • все типы и идентификаторы полностью известны и будут известны во время компиляции. Это кажется очевидным, но я предпочитаю это объяснить.
Для меня это означает, что вариант переключения является концептуально правильным решением, хотя и чрезвычайно многословным и подвержен ошибкам. Моя цель состоит в том, чтобы реорганизовать эти функции так, чтобы мне нужно было только один раз закодировать логику случая, а затем я мог сосредоточиться на перечислении ассоциации типа идентификатора где-то еще. Все это должно быть доступно без какого-либо снижения производительности, а это означает, что полностью оптимизированный код должен использовать таблицу переходов.
Теперь предположим, что у меня есть некоторый шаблонный obj_type_t, который "возвращает" тип, соответствующий идентификатору (как это построить, будет темой другого вопроса), и давайте сосредоточимся на случае переключения.
Мой решения
Мой простой подход заключался в использовании рекурсии шаблона для автоматического создания случая переключения:

Код: Выделить всё

// Base case
template 
void generateSwitch(T i, std::integer_sequence, Predicate&& predicate, DefaultPredicate&& defaultPredicate)
{
defaultPredicate();
}

// Recursive step
template 
void generateSwitch(T i, std::integer_sequence, Predicate&& predicate, DefaultPredicate&& defaultPredicate)
{
if (i == First)
{
predicate(First);
}
else
{
generateSwitch(i, std::integer_sequence{}, predicate, defaultPredicate);
}
}
Чтобы я мог использовать его следующим образом:

Код: Выделить всё

void dispatch(const Buffer& buffer)
{
auto processBuffer = [buffer](auto Id) // this auto is actually an integral_constant, so it's ok to use it as a template parameter
{
obj_type_t obj;
obj.deserialize(buffer);
// other code to print and process the buffer
};

auto invalidId = [](){ std::cout 

Подробнее здесь: [url]https://stackoverflow.com/questions/79145159/compile-time-generated-switch-case-with-no-performance-hit[/url]
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C++»