Верно, если вы хотите, чтобы разные перечисления в одной и той же области имели «последний» член, это невозможно сделать. В этом случае вам потребуется префикс этого «последнего» значения, например, с именем перечисления (аналогично второму примеру перечисления.
Что касается «последней» записи для проверки аргументов, возможно, я упустил вашу точку зрения. Например, если вы передаете перечисление в качестве аргумента функции, например
void f( enum fileType type )
Он не обеспечивает большей «безопасности типов», чем fileType без «последнего» элемента.
Единственная причина, которую я вижу для последнего элемента (а затем и для первого элемента!), Заключается в том, что вы хотите перебирать элементы перечислимых элементов в цикле. Например:
enum E
{
first,
e1 = first,
e2,
e3,
last
}
for (int i = first; i < last; ++i)
...
если это так, разве не достаточно искусственно хотеть, чтобы два разных перечисления имели один и тот же именованный «последний» элемент в списке? В чем преимущество наличия одного «последнего» в двух разных перечислениях?
Улучшает ли это удобочитаемость по сравнению, например, с имея E_last и F_last?
Или это помогает сохранить написание хотя бы одной строки кода?
Кроме того, для чего используется 'last' в перечислениях с определенными областями? Перечисления с областью видимости не преобразуются в int по умолчанию. (Но, может быть, я неправильно понял, что вы хотели сделать ...)
О "Вы не можете держать значения enum короткими ..." Боюсь, я не понял, что вы хотели сказать здесь. Было ли во мне использование «const unsigned short» в примере с константой?
Также не поймите меня неправильно, в вашем случае (желая обрабатывать типы файлов) я выступал за использование константных групп. И с ними легко и естественно использовать один и тот же «первый» и «последний» член (но с разными значениями) в разных группах. Смотри
namespace nms
{
typedef const unsigned short G1_t
namespace G1
{
G1_t first = 1;
G1_t type1 = 1;
G1_t type2 = 2;
G1_t type3 = 3;
G1_t last = 3;
}
typedef const long G2_t
namespace G2
{
G1_t first = -1;
G1_t obj1 = -1;
G1_t obj2 = 0;
G1_t obj3 = 1;
G1_t last = 1;
}
}
Что касается «namespace - namespace - enum», мне не нравится дополнительная косвенность без существенных преимуществ. Что касается «namespace - struct / class - enum», то оно более философское:
C - это, так сказать, гладкий и быстрый мотоцикл, который делает написание ассемблерного кода практически ненужным. Это также в значительной степени принадлежит оператору C cast, который позволяет полностью сбросить безопасность типов и делать то, что вы хотите, не мешая компилятору.
C ++ по-прежнему любит быть супер-набором C. Он добавил классы и объектно-ориентированное программирование, но все же хотел оставить мотоцикл. Что было хорошо. Теперь добавление большего количества «типобезопасных» перечислений с ограниченным диапазоном, сохраняя при этом операторы броска, выглядит для меня как желание добавить подушки безопасности и ремни безопасности на мотоцикл.
Я не против пересмотра перечислений, чтобы получить лучшие перечисления (если это действительно необходимо), но если кто-то делает это, то следует также время от времени (например, каждые 5 лет) отбрасывать вещи, которые теперь признаны старыми, устаревшими и злыми. В противном случае язык становится все более и более загроможденным, а начинающим еще труднее учиться. И, как и любой инструмент, языки программирования должны быть просты в использовании, и это включает в себя отсутствие дюжины способов сделать то же самое.