Почему я не могу увеличивать переменную перечислимого типа?
У меня есть перечисляемый тип 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;
}