Обработать каждый вариант enum

98
05 мая 2021, 11:20

Если enum Oper порядка 30 штук. Есть метод класса, которая принимает параметр Oper и работает с полями класса. Каждый случай обрабатывается по разному.

  1. Какая реализация someFuncX быстрее?
  2. Есть ли подводные камни в реализации через лямды-выражения?
  3. Общие советы. Например знаю что если делать через switch, то IDE подсказывает, если не все возможные enum отработаны.
  4. Имеет ли смысл делать std::array статическим для выигрыша скорости?
  5. Тоже будет справедливым, если enum Oper будет длиною 300 элементов?

Пример кода:

class C {
    int someField;
    enum class Oper {
        op1, op2, /*...,*/ op30
    };
    void someFuncIf (Oper o) {
        if (o == Oper::op1) {
            ++someField;
            /* some code 1*/
        } else if (o == Oper::op2) {
            --someField;
            /* some code 2*/
        } /*else if { ... }*/
        else if (o == Oper::op30) {
            someField *= 2;
            /* some code 30*/
        } else {
            assert(false);
        }
    }
    void someFuncSwitch (Oper o) {
        switch(o) {
        case Oper::op1:
            ++someField;
            /* some code 1*/
            break;
        case Oper::op2:
            --someField;
            /* some code 2*/
            break;
        /*case ...*/
        case Oper::op30:
            someField *= 2;
            /* some code 30*/
            break;
        }
    }
    void someFuncLambda (Oper o) {
        auto op0 = [this] () { ++someField; /* some code 1*/ }; // для инициализации array. Не знаю как по другому.
        std::array<decltype (op0()), static_cast<uint>(Oper::cntOper)> array;
        array[static_cast<uint>(Oper::op1)] = [this] () { ++someField; /* some code 1*/ };
        array[static_cast<uint>(Oper::op2)] = [this] () { --someField; /* some code 2*/ };
       // ...
        array[static_cast<uint>(Oper::op30)] = [this] () { someField *= 2; /* some code 30*/ };
        array[static_cast<uint>(o)]();
    }
};
Answer 1

Есть несколько методов, позволяющих сделать реализацию

  1. Обычно компиляторы довольно хорошо реализуют switch, применяя там как jmp-таблицы (самый самый быстрый способ, но недостаток - фрагментация, т.е. куча нулей если есть разрывы между swith) так и "двоичный" поиск. Я советую использовать именно switch в большинстве функций выбора.
  2. if подходит если, а)можно построить двоичное дерево поиска б)разброс между параметрами большой, в) разброс параметров можно описать легко-вычисляемой функцией или обьеденить в выражение, например все четные елементы, или все отрицательные, г)если мало условий. В большинстве случаев if даст не очень хорошие результаты, но в отдельных случаях (например вычислить в сколько бит можно записать число от 0 до 255 - можно строеным if) он даёт довольно хороший результат.

  3. Можно задать массив функций. Массив функций работает чуть медленнее чем jmp-таблица, из минусов - нужна сплошная заполненность таблицы функциями на диапазоне перехода (эту проблему решает map). Несуществующие случаи прийдется заполнять либо пустой функцией (dummy), либо нулями - и отбрасывать дополнительным if. Если есть возможность построить такой массив - то он будет работать либо быстрее чем switch, либо почти одинаково (при условии что оптимизатор правильно реализует switch).

  4. map - это массив ключ-значение. Вначале будет сделан поиск елемента по-ключу, а потом вызов функции. Поэтому будет работать немного медленне чем метод 3, и я думаю switch его победит по скорости (при наличии хорошего оптимизатора для вашей среды). В отдельных случаях этот метод может дать результаты лучше чем switch (если оптимизатор плохой) и if. Так же вопрос про оптимальность map http://stackoverflow.com/questions/931890/what-is-more-efficient-a-switch-case-or-an-stdmap
Answer 2

В вашем случае с enum однозначно делайте switch.

Во-первых, всем программерам понятно, а во-вторых -- быстрее не бывает.

Как для 30, так и для 300 (и даже 2300 (более не проверял)) с небольшими "дырами" в значениях case, по крайней мере gcc, делает таблицу адресов меток, выбирает по индексу из нее адрес метки и делает jmp на нее.

READ ALSO
Выход за пределы массива в cuda

Выход за пределы массива в cuda

Начинаю осваивать cuda и при работе с блоками и нитями задался вопросом что происходит в случае выхода за пределы массиваТобишь, допустим,...

86
С++ Как сделать белый список для строки

С++ Как сделать белый список для строки

Хотел бы спроситькак сделать белый список для строки?Ну то есть есть слова которые можно писать в этой строке и если в строке обнаружено слово...

104
Удаление последнего элемента в списке

Удаление последнего элемента в списке

Прошу не ругать если я что-то не так объяснил, мне 15 летЯ увлекаюсь программированием на языке С++

104
Как получить кол-во элементов массива

Как получить кол-во элементов массива

Допустим, есть матрица

72