Как я могу перебрать перечисление? - PullRequest
262 голосов
/ 04 ноября 2008

Я только что заметил, что вы не можете использовать стандартные математические операторы для перечисления, такие как ++ или + =

Так, каков наилучший способ перебрать все значения в перечислении C ++?

Ответы [ 17 ]

2 голосов
/ 30 мая 2016

Если вы не хотите загрязнять свой enum конечным элементом COUNT (потому что, возможно, если вы также используете enum в переключателе, тогда компилятор предупредит вас о пропущенном регистре COUNT :), вы можете сделать это:

enum Colour {Red, Green, Blue};
const Colour LastColour = Blue;

Colour co(0);
while (true) {
  // do stuff with co
  // ...
  if (co == LastColour) break;
  co = Colour(co+1);
}
1 голос
/ 08 ноября 2018

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

enum Bar {
    One = 1,
    Two,
    Three,
    End_Bar // Marker for end of enum; 
};

for (Bar foo = One; foo < End_Bar; foo = Bar(foo + 1))
{
    // ...
}
1 голос
/ 14 февраля 2016

Для MS-компиляторов:

#define inc_enum(i) ((decltype(i)) ((int)i + 1))

enum enumtype { one, two, three, count};
for(enumtype i = one; i < count; i = inc_enum(i))
{ 
    dostuff(i); 
}

Примечание: это намного меньше кода, чем простой шаблонный пользовательский ответ итератора.

Вы можете заставить это работать с GCC, используя typeof вместо decltype, но у меня пока нет под рукой этого компилятора, чтобы убедиться, что он компилируется.

0 голосов
/ 28 мая 2019
enum class A {
    a0=0, a3=3, a4=4
};
constexpr std::array<A, 3> ALL_A {A::a0, A::a3, A::a4}; // constexpr is important here

for(A a: ALL_A) {
  if(a==A::a0 || a==A::a4) std::cout << static_cast<int>(a);
}

A constexpr std::array может выполнять итерации даже непоследовательных перечислений без создания экземпляра массива компилятором. Это зависит от таких вещей, как эвристика оптимизации компилятора и от того, берете ли вы адрес массива.

В моих экспериментах я обнаружил, что g++ 9.1 с -O3 оптимизирует вышеприведенный массив, если есть 2 непоследовательных значения или довольно много последовательных значений (я проверял до 6). Но он делает это только в том случае, если у вас есть оператор if. (Я пробовал оператор, который сравнивал целочисленное значение больше, чем все элементы в последовательном массиве, и он включал итерацию, хотя ни один из них не был исключен, но когда я пропустил оператор if, значения были помещены в память.) значения из непоследовательного перечисления в [одном случае | https://godbolt.org/z/XuGtoc]. Я подозреваю, что это странное поведение связано с глубокой эвристикой, связанной с кэшем и предсказанием ветвлений.

Вот ссылка на простую тестовую итерацию для godbolt , демонстрирующую, что массив не всегда создается.

Ценой этой техники является написание элементов enum дважды и синхронизация двух списков.

0 голосов
/ 15 марта 2018

Просто создайте массив целых и сделайте цикл по массиву, но заставьте последний элемент сказать -1 и используйте его для условия выхода.

Если enum:

enum MyEnumType{Hay=12,Grass=42,Beer=39};

затем создайте массив:

int Array[] = {Hay,Grass,Beer,-1};

for (int h = 0; Array[h] != -1; h++){
  doStuff( (MyEnumType) Array[h] );
}

Это не ломается независимо от целых чисел в представлении, если проверка -1 не вступает в противоречие с одним из элементов курса.

0 голосов
/ 31 июля 2016

Если вы знали, что значения перечисления были последовательными, например, перечисление Qt: Key, вы могли бы:

Qt::Key shortcut_key = Qt::Key_0;
for (int idx = 0; etc...) {
    ....
    if (shortcut_key <= Qt::Key_9) {
        fileMenu->addAction("abc", this, SLOT(onNewTab()),
                            QKeySequence(Qt::CTRL + shortcut_key));
        shortcut_key = (Qt::Key) (shortcut_key + 1);
    }
}

Работает как положено.

0 голосов
/ 04 ноября 2008

C ++ не имеет самоанализа, поэтому вы не можете определять подобные вещи во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...