(Как) я могу подсчитать элементы в перечислении?
Этот вопрос пришел мне на ум, когда у меня было что-то вроде
enum Folders {FA, FB, FC};
и хотел создать массив контейнеров для каждой папки:
ContainerClass*m_containers[3];
....
m_containers[FA] = ...; // etc.
(Использование карт гораздо более элегантно для использования: std::map<Folders, ContainerClass*> m_containers;
)
Но вернемся к моему оригинальному вопросу: что, если я не хочу жестко закодировать размер массива, есть ли способ выяснить, сколько элементов находится в папках? (Не полагаясь, например, на FC
, последний элемент в списке, который позволит что-то вроде ContainerClass*m_containers[FC+1]
, если я не ошибаюсь.)
Ответы
Ответ 1
Там не очень хороший способ сделать это, обычно вы видите дополнительный элемент в перечислении, т.е.
enum foobar {foo, bar, baz, quz, FOOBAR_NR_ITEMS};
Итак, вы можете сделать:
int fuz[FOOBAR_NR_ITEMS];
Тем не менее, не очень приятно.
Но, конечно, вы понимаете, что просто количество элементов в перечислении небезопасно, например,
enum foobar {foo, bar = 5, baz, quz = 20};
количество элементов будет равно 4, но целочисленные значения значений перечисления будут выходными из диапазона индекса массива. Использование значений перечисления для индексации массивов небезопасно, вам следует рассмотреть другие варианты.
edit: в соответствии с запросом добавлена специальная запись.
Ответ 2
Для С++ существуют различные методы типа безопасных перечислений, а некоторые из них (например, предлагаемые, но никогда не представленные Boost.Enum) включают поддержку для получения размера перечисления.
Самый простой подход, который работает как на C, так и на С++, заключается в принятии соглашения о объявлении значения... MAX для каждого из ваших типов перечислений:
enum Folders { FA, FB, FC, Folders_MAX = FC };
ContainerClass *m_containers[Folders_MAX + 1];
....
m_containers[FA] = ...; // etc.
Изменить. Что касается { FA, FB, FC, Folders_MAX = FC}
по сравнению с {FA, FB, FC, Folders_MAX]
: я предпочитаю устанавливать значение MAX для последнего юридического значения перечисления по нескольким причинам:
- Имя константы технически более точно (поскольку
Folders_MAX
дает максимально возможное значение перечисления).
- Лично мне кажется, что
Folders_MAX = FC
выделяется из других записей немного больше (что делает его немного сложнее случайно добавить значения перечисления без обновления максимального значения, проблема, на которую ссылается Martin York).
- GCC содержит полезные предупреждения, такие как "значение перечисления, не включенное в коммутатор" для кода, такого как следующее. Предоставление Folders_MAX == FC + 1 прерывает эти предупреждения, так как в итоге вы получаете множество... MAX значений перечисления, которые никогда не должны включаться в коммутатор.
switch (folder)
{
case FA: ...;
case FB: ...;
// Oops, forgot FC!
}
Ответ 3
Как насчет черт, в стиле STL? Например:
enum Foo
{
Bar,
Baz
};
напишите
std::numeric_limits<enum Foo>::max()
специализация (возможно, constexpr, если вы используете С++ 11). Затем в вашем тестовом коде укажите любые статические утверждения для сохранения ограничений, которые std:: numeric_limits:: max() = last_item.
Ответ 4
Добавьте запись в конце вашего перечисления под названием Folders_MAX или что-то подобное и используйте это значение при инициализации массивов.
ContainerClass* m_containers[Folders_MAX];
Ответ 5
Мне нравится использовать перечисления в качестве аргументов для моих функций. Это простое средство для предоставления фиксированного списка "вариантов". Проблема с верхним голосовым ответом здесь заключается в том, что, используя это, клиент может указать "недопустимый вариант". Как побочный эффект, я рекомендую делать по существу то же самое, но использовать константу int вне enum, чтобы определить их количество.
enum foobar { foo, bar, baz, quz };
const int FOOBAR_NR_ITEMS=4;
Это не приятно, но это чистое решение, если вы не изменяете перечисление без обновления константы.
Ответ 6
Я действительно не вижу никакого способа действительно получить число значений в перечислении в С++. Любое из решений, упомянутых выше, работает до тех пор, пока вы не определяете значение своих перечислений, если вы определяете значение, которое может возникнуть в ситуациях, когда вы создаете массивы слишком большими или слишком маленькими.
enum example{ test1 = -2, test2 = -1, test3 = 0, test4 = 1, test5 = 2 }
в этом примере в примерах будет создан массив из 3 элементов, когда вам понадобится массив из 5 элементов
enum example2{ test1 , test2 , test3 , test4 , test5 = 301 }
в этом примере примеры приведут к созданию массива из 301 элемента, когда вам понадобится массив из 5 элементов
Лучший способ решить эту проблему в общем случае - это перебирать по вашим перечислениям, но это не соответствует стандарту, насколько я знаю.
Ответ 7
Для С++ 17 вы можете использовать magic_enum::enum_count
из lib https://github.com/Neargye/magic_enum:
magic_enum::enum_count<Example>()
→ 4.