c ++ 11 — Можно ли определить количество элементов перечислимого класса c ++?

Можно ли определить мощность c ++ enum class:

enum class Example { A, B, C, D, E };

Я пытался использовать sizeofоднако он возвращает размер элемента enum.

sizeof(Example); // Returns 4 (on my architecture)

Есть ли стандартный способ получить мощность (5 в моем примере)?

42

Решение

Не напрямую, но вы могли бы использовать следующий прием:

enum class Example { A, B, C, D, E, Count };

Тогда мощность доступна как (int)Example::Count,

Конечно, это работает хорошо, только если вы позволяете автоматически присваивать значения перечисления, начиная с 0. Если это не так, вы можете вручную назначить правильное количество элементов для Count, что на самом деле не отличается от необходимости поддерживать отдельную константу тем не мение:

enum class Example { A = 1, B = 2, C = 4, D = 8, E = 16, Count = 5 };

Недостатком является то, что компилятор позволит вам использовать Example::Count в качестве аргумента для значения перечисления — так что будьте осторожны, если вы используете это! (Лично я считаю, что на практике это не является проблемой.)

49

Другие решения

constexpr auto TEST_START_LINE = __LINE__;
enum class TEST { // Subtract extra lines from TEST_SIZE if an entry takes more than one
ONE = 7
, TWO = 6
, THREE = 9
};
constexpr auto TEST_SIZE = __LINE__ - TEST_START_LINE - 3;

Это происходит от UglyCoder’s answer но улучшает это тремя способами.

  • В перечислении type_safe нет дополнительных элементов (BEGIN а также SIZE) (Ответ Кэмерон также есть эта проблема.)
    • Компилятор не будет жаловаться на их отсутствие в операторе switch (существенная проблема)
    • Они не могут быть случайно переданы функциям, ожидающим вашего перечисления. (не частая проблема)
  • Не требует литья для использования. (Ответ Кэмерон имеет эту проблему тоже.)
  • Вычитание не влияет на размер класса перечисления.

Сохраняет UglyCoder-х преимущество перед Ответ Кэмерон что перечислителям могут быть присвоены произвольные значения.

Проблема (поделился с UglyCoder но не с Cameron) делает новые строки и комментарии значимыми … что неожиданно. Таким образом, кто-то может добавить запись с пробелами или комментарий без настройки TEST_SIZEрасчет.

11

enum class TEST
{
BEGIN = __LINE__
, ONE
, TWO
, NUMBER = __LINE__ - BEGIN - 1
};

auto const TEST_SIZE = TEST::NUMBER;

// or this might be better
constexpr int COUNTER(int val, int )
{
return val;
}

constexpr int E_START{__COUNTER__};
enum class E
{
ONE = COUNTER(90, __COUNTER__)  , TWO = COUNTER(1990, __COUNTER__)
};
template<typename T>
constexpr T E_SIZE = __COUNTER__ - E_START - 1;
7

Один из приемов, который вы можете попробовать, — это добавить значение enum в конец списка и использовать его в качестве размера. В вашем примере

enum class Example { A, B, C, D, E, ExampleCount };
3

Существует один трюк, основанный на X () — макросах: image, у вас есть следующее перечисление:

enum MyEnum {BOX, RECT};

Переформатируйте это, чтобы:

#define MyEnumDef \
X(BOX), \
X(RECT)

Затем следующий код определяет тип перечисления:

enum MyEnum
{
#define X(val) val
MyEnumDef
#undef X
};

А следующий код вычисляет количество элементов enum:

template <typename ... T> void null(T...) {}

template <typename ... T>
constexpr size_t countLength(T ... args)
{
null(args...); //kill warnings
return sizeof...(args);
}

constexpr size_t enumLength()
{
#define XValue(val) #val
return countLength(MyEnumDef);
#undef XValue
}

...
std::array<int, enumLength()> some_arr; //enumLength() is compile-time
std::cout << enumLength() << std::endl; //result is: 2
...
2

Нет, вы должны написать это в коде.

1

Вы также можете рассмотреть static_cast<int>(Example::E) + 1 который устраняет лишний элемент.

1