(Как) я могу подсчитать элементы в перечислении?

Этот вопрос пришел мне на ум, когда у меня было что-то вроде

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 элементов

Лучший способ решить эту проблему в общем случае - это перебирать по вашим перечислениям, но это не соответствует стандарту, насколько я знаю.