(Как) я могу посчитать предметы в перечислении? - PullRequest
89 голосов
/ 20 января 2010

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

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], если я не ошибаюсь.)

Ответы [ 6 ]

114 голосов
/ 20 января 2010

Не очень хороший способ сделать это, обычно вы видите дополнительный элемент в enum, т.е.

enum foobar {foo, bar, baz, quz, FOOBAR_NR_ITEMS};

Итак, вы можете сделать:

int fuz[FOOBAR_NR_ITEMS];

Все еще не очень хорошо, хотя.

Но, конечно, вы понимаете, что просто количество элементов в перечислении небезопасно, например,

enum foobar {foo, bar = 5, baz, quz = 20};

количество элементов будет равно 4, но целочисленные значения значений перечисления будут выходить за пределы диапазона индекса массива. Использование перечислимых значений для индексации массива небезопасно, вам следует рассмотреть другие варианты.

edit: в соответствии с запросом выделил специальную запись больше.

32 голосов
/ 20 января 2010

Для C ++ доступны различные типобезопасные методы перечисления , и некоторые из них (например, предложенный, но никогда не представленный Boost.Enum ) включают поддержку получить размер перечисления.

Самый простой подход, который работает как в C, так и в 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 на последнее допустимое значение перечисления по нескольким причинам:

  1. Имя константы технически более точно (поскольку Folders_MAX дает максимально возможное значение enum).
  2. Лично я чувствую, что Folders_MAX = FC выделяется среди других записей чуть больше (что усложняет случайное добавление значений enum без обновления максимального значения, проблема, на которую ссылается Мартин Йорк).
  3. GCC содержит полезные предупреждения, такие как «значение перечисления, не включенное в переключатель» для кода, такого как следующий. Разрешение Folders_MAX == FC + 1 снимает эти предупреждения, так как в итоге вы получаете кучу ... значений перечисления MAX, которые никогда не должны включаться в переключатель.
switch (folder) 
{
  case FA: ...;
  case FB: ...;
  // Oops, forgot FC!
}
7 голосов
/ 23 декабря 2014

Как насчет черт в стиле STL? Например:

enum Foo
{
    Bar,
    Baz
};

написать

std::numeric_limits<enum Foo>::max()

специализация (возможно, constexpr, если вы используете c ++ 11). Затем в своем тестовом коде предоставьте все статические утверждения для поддержки ограничений, которые std :: numeric_limits :: max () = last_item.

3 голосов
/ 20 января 2010

Добавьте в конец вашего перечисления запись с именем Folders_MAX или чем-то похожим и используйте это значение при инициализации ваших массивов.

ContainerClass* m_containers[Folders_MAX];
2 голосов
/ 14 ноября 2017

Мне нравится использовать перечисления в качестве аргументов для моих функций. Это простой способ предоставить фиксированный список «опций». Проблема с ответом, получившим наибольшее количество голосов, заключается в том, что с его помощью клиент может указать «недопустимую опцию». В качестве побочного результата я рекомендую делать по существу то же самое, но использовать константу int вне перечисления, чтобы определить их количество.

enum foobar { foo, bar, baz, quz };
const int FOOBAR_NR_ITEMS=4;

Это не приятно, но это чистое решение, если вы не измените enum без обновления константы.

1 голос
/ 13 января 2015

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

enum example{ test1 = -2, test2 = -1, test3 = 0, test4 = 1, test5 = 2 }

в приведенных ниже примерах результат будет создавать массив из 3 элементов, если вам нужен массив из 5 элементов

enum example2{ test1 , test2 , test3 , test4 , test5 = 301 }

в приведенных ниже примерах будет создан массив из 301 элемента, если вам нужен массив из 5 элементов

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

...