Ответ 1
enum Some
{
Some_first_ = 0,
Some_Alpha = Some_first_,
....
Some_last_
};
Выполняя такое вы можете предоставить первый и последний, никогда не меняет порядок
У меня есть код С++, в котором объявлено следующее перечисление:
enum Some
{
Some_Alpha = 0,
Some_Beta,
Some_Gamma,
Some_Total
};
int array[Some_Total];
Значения Alpha, Beta и Gamma являются последовательными, и я с удовольствием использую следующий цикл для итерации через них:
for ( int someNo = (int)Some_Alpha; someNo < (int)Some_Total; ++someNo ) {}
Этот цикл в порядке, пока я не решит изменить порядок объявлений в перечислении, скажем, сделать Beta первым значением, а Alpha - вторым. Это делает недействительным заголовок цикла, потому что теперь мне нужно перебирать с Beta на Total. Итак, каковы наилучшие методы повторения через enum? Я хочу перебирать все значения без изменения заголовков циклов каждый раз. Я могу думать о одном решении:
enum Some
{
Some_Start = -1,
Some_Alpha,
...
Some_Total
};
int array[Some_Total];
и итерации от (Start + 1) до Total, но это кажется уродливым, и я никогда не видел, чтобы кто-то делал это в коде. Есть ли известная парадигма для повторения через перечисление, или мне просто нужно исправить порядок значений перечисления? (пусть притворяется, у меня действительно есть некоторые удивительные причины для изменения порядка значений enum)...
enum Some
{
Some_first_ = 0,
Some_Alpha = Some_first_,
....
Some_last_
};
Выполняя такое вы можете предоставить первый и последний, никогда не меняет порядок
Вы можете определить operator++()
для вашего enum
. Это имеет то преимущество, что использует известную парадигму стандартных операторов инкрементации. :)
В зависимости от того, являются ли ваши перечисления смежными, вы можете рассматривать их как int
или использовать переключатель:
Some& operator++(Some& obj)
{
# if YOUR_ENUMS_ARE_CONTIGUOUS
int i = obj;
if( ++i > Some_Total ) i = Some_Alpha;
return obj = static_cast<Some>(i);
# else
switch(obj)
{
case Some_Alpha : obj = Some_Beta; break;
case Some_Beta : obj = Some_Gamma; break;
case Some_Gamma : obj = Some_Total; break;
case Some_Total : obj = Some_Alpha; break;
default: assert(false); // changed enum but forgot to change operator
}
return obj;
# endif
}
Обратите внимание, что если operator++()
определен, пользователи, вероятно, ожидают и operator--()
.
Нет, нет никакого способа сделать это, потому что нет гарантии, что кто-то не написал такой код:
enum Some
{
Some_Alpha = 0,
Some_Beta,
Some_Gamma = 42,
Some_Delta,
Some_Total
};
Вы можете проверить эту статью с ее исходный код о том, как вы можете реализовать это со статическими членами класса.
В С++ 11 (и, возможно, ранее) вы можете использовать следующий хак, чтобы сделать Some
iterable:
Some operator++(Some& s) {
return s = (Some )(std::underlying_type<Some>::type(x) + 1);
}
Some operator*(Some s) {
return s;
}
Some begin(Some s) {
return Some_Alpha;
Some end(Some s) {
return Some_Gamma;
}
int main() {
// the parenthesis here instantiate the enum
for(const auto& s : Some()) {
// etc. etc.
}
return 0;
}
(Этот ответ был бесстыдно адаптирован из здесь.)
Если вы не используете никаких назначений, перечисления гарантированно будут последовательно, начиная с 0 в качестве первого. Про ч ее.
Лучшее, что вы можете сделать, это сохранить их в том порядке, в котором вы хотите, в определении вашего перечисления, и прокручивать их с помощью цикла for.
Я помещаю все Enums в собственное пространство имен. Пример:
namespace Foo {
enum Enum {
First=0, // must be sequential
Second,
Third,
End // must be last
};
}
В коде:
for (int i=Foo::First; i!=Foo::End; i++) {
// do stuff
}
Это потому, что С++ разрешает такие вещи (не тестируемые в компиляторе):
enum Foo {
Alpha = 1
};
enum Bar {
Beta = 2
};
Foo foo = Beta;
Это явно неправильно.