Почему я не могу увеличивать переменную перечислимого типа?

У меня есть перечисляемый тип StackID, и я использую перечисление, чтобы ссылаться на индекс конкретного вектора, и это облегчает чтение моего кода.

Однако теперь мне нужно создать переменную типа nextAvail типа StackID. (на самом деле это относится к определенному идентификатору stackID). Я попытался увеличить его, но на С++, это незаконно:

nextAvail++;

Какой вид имеет смысл для меня... потому что нет ограничений на проверку.

Я, вероятно, не замечаю ничего очевидного, но какая хорошая замена?


Я также хочу обратиться к этому вопросу.

Ответ 1

Я, вероятно, не замечаю ничего очевидного, но какая хорошая замена?

Перегрузка operator++:

// Beware, brain-compiled code ahead! 
StackID& operator++(StackID& stackID)
{
#if MY_ENUMS_ARE_CONTIGUOUS && I_DO_NOT_WORRY_ABOUT_OVERFLOW
  return stackID = static_cast<StackID>( ++static_cast<int>(stackID) );
#else
  switch(stackID) {
    case value1 : return stackID = value2;
    case value2 : return stackID = value3;
    ...
    case valueN : return stackID = value1;
  }
  assert(false);
  return stackID; // some compilers might warn otherwise
#endif
}

StackID operator++(StackID& stackID, int)
{
  StackID tmp(stackID);
  ++stackID;
  return tmp;
}

Ответ 2

Потому что перечисления не обязательно должны быть смежными. Например. возьмите этот пример:

enum Colors {
 cRed, // = 0
 cBlue, // = 1
 cGreen = 3
}

Что должно произойти в этом сценарии?

Colors color = cBlue;
Colors other = color++;

Должно ли другое быть cGreen или должно быть равно 2. В этом случае это не действительный член перечисления больше. Как насчет этого?

Colors color = cGreen;
Colors other = color++;

Должно other быть cRed (обернуть) или 4?

Как вы можете видеть, возможность увеличения значений перечисления вводит множество вопросов и усложняет простой механизм, который они намереваются быть.

Если все, о чем вы заботитесь, - это целочисленное значение, увеличивающееся, просто добавьте к int и увеличивайте его.

Ответ 3

Отбрасывание назад и вперед в/из int - это, конечно, очевидное решение, тогда вы четко указываете, что вы понимаете, что добавление происходит "снаружи" enum:

nextAvail = static_cast<StackID>(static_cast<int>(nextAvail) + 1);

Ответ 4

Почему бы не сохранить nextAvail как int вместо этого, если вы собираетесь выполнять арифметические операции над ним?

Другой вариант - обернуть перечисление в свой собственный тип и перегрузить operator ++ для него (которое также может обернуться вокруг или что-то вроде этого).

Ответ 5

Перечисление семантически предполагается представлять набор различных связанных значений.

Итак, у вас может быть

enum Colour {RED, GREEN, BLUE};

Но это должно быть эквивалентно:

enum Colour {GREEN, BLUE, RED};

Проблема заключается в том, что если вы увеличиваете перечисление, то эти представления не совпадают. GREEN ++ в первом случае не совпадает с GREEN ++ во втором.

Приведение вашей программы в зависимость от объявления перечисления - это рецепт для бедствия. Сторонники могут предположить, что порядок перечисления не имеет значения, вводя много тихих ошибок.

Ответ 6

Перечисления будут иметь тип int, поэтому вы можете их отличать. Это то, что вы пытаетесь сделать?

int ndx = (int) StackID.SomeValue;
...
++ndx;

Это, конечно, сделает человека очень смущенным по линии.

Мне кажется, что вы используете enum, где вы должны использовать const или даже #define. enum наиболее подходит, когда у вас есть произвольные значения (где точное значение не имеет смысла).

Ответ 7

Что касается oprator ++, то состояния $5.2.6/1 - "Тип операнда должен быть арифметическим типом или указателем на полный тип объекта".

StackID не соответствует этому счету. Это тип перечисления.

Один вариант похож на этот

$5.7/1 - "Для добавления оба операнда должны иметь тип арифметики или перечисления, или один операнд должен быть указателем на полностью определенный тип объекта, а другой должен иметь интегральный или перечисляемый тип".

enum Possibility {Yes, No, Maybe};

Possibility operator++(Possibility const& r){
   return Possibility(r + 1);   // convert r to integer, add 1, convert back to Enum
}

int main(){
   Possibility p = Yes;
   Possibility p1 = ++p;
}