¿Por qué no puedo incrementar una variable de un tipo enumerado?

8 minutos de lectura

avatar de usuario
BeeBand

Tengo un tipo enumerado StackIDy estoy usando la enumeración para referirme a un índice de un vector en particular y hace que mi código sea más fácil de leer.

Sin embargo, ahora tengo la necesidad de crear una variable llamada nextAvail de tipo StackID. (en realidad se refiere a un stackID en particular). Traté de incrementarlo pero en C++, lo siguiente es ilegal:

nextAvail++;

Lo cual tiene sentido para mí… porque no hay verificación de límites.

Probablemente estoy pasando por alto algo obvio, pero ¿cuál es un buen sustituto?


También quiero vincular a esta pregunta.

avatar de usuario
sbi

Probablemente estoy pasando por alto algo obvio, pero ¿cuál es un buen sustituto?

Sobrecarga 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;
}

  • @sbi: ciertamente me simplificaría las cosas hacer esto. pero que les dices a los carteles que sugieren que un enum está destinado a expresar un conjunto de valores arbitrarios?

    – BeeBand

    13 de agosto de 2010 a las 8:57

  • @BeeBand: si hay algún uso para el ‘++’, supongo que tiene una buena razón para ir más allá del uso convencional de C ++ de enumeraciones como entradas verificadas en tiempo de compilación. Por otro lado, al código de Sbi le vendría bien una verificación de límites. En Java, las enumeraciones son solo una especie de clases livianas con miembros no modificables; es una práctica aceptada colocar métodos en ellas. Ver download.oracle.com/javase/1.5.0/docs/guide/language/enums.html.

    – tucuxi

    13 de agosto de 2010 a las 9:05

  • @BeeBand: No estoy de acuerdo. Probablemente cinco de cada diez libros de texto. enum los ejemplos son algo asi enum month { Jan, Feb, ..., Dec }; y por lo tanto un ejemplo perfecto para enumeraciones que pueden incrementarse. Durante los últimos >15 años de hacer C++, he sobrecargado operator++ para enumeraciones probablemente menos de cinco veces. Pero yo tener hecho.

    – sbi

    13 de agosto de 2010 a las 9:06


  • @GMan y @Martin: <sigh> ¿Puedes decir que estoy de vacaciones, sentado en el jardín, con mi computadora portátil sobre mis rodillas dos veces al día y me da pereza encender el compilador? @BeeBand: Lo siento por joder esto tan mal. Afortunadamente, la comunidad los detecta.

    – sbi

    13 de agosto de 2010 a las 16:26

  • @Streppel: ¡Gracias! (Por supuesto, dado que califiqué mi código con una advertencia, no me siento mal por perder una llave… :´^> )

    – sbi

    30 de enero de 2014 a las 9:47

Porque las enumeraciones no tienen que ser contiguas. Por ejemplo, tome este ejemplo:

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

¿Qué debería pasar en este escenario?

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

¿Debería ser otro? cGreen o debería ser 2. En ese caso, ya no es un miembro de enumeración válido. ¿Qué pasa con esto?

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

Debería other ser cRed (envolver alrededor) o 4?

Como puede ver, poder incrementar los valores de enumeración presenta muchas preguntas y complica el mecanismo simple que pretenden ser.

Si todo lo que le importa es que el valor entero se incremente, entonces simplemente convierta a int e incrementar eso.

  • @Igor: ahora reemplaza tu ejemplo con esto: enum month .... Los meses son contiguos y se incrementan naturalmente. ¿Entonces que?

    – sbi

    13 de agosto de 2010 a las 9:11

  • @sbi: Oh meses, eso cambia todo porque los meses son simples. . . espera, ¿qué sucede cuando incrementas diciembre? ¿Debería lanzar una excepción de desbordamiento, o debería darse la vuelta? Puede ser obvio para usted lo que sucede, pero es posible que requiera una funcionalidad diferente. Hay demasiadas preguntas sobre cómo esto debería trabajo, los diseñadores del lenguaje estaban en lo correcto al no permitir esto y dejar que cada caso se manejara individualmente.

    – Preocupado binario

    13 de agosto de 2010 a las 9:25


  • @Ígor: ¡Gracias! Creo que su respuesta es extremadamente útil, sin embargo, he aceptado la de sbi. Creo que hice un poco de trampa aquí, ya que básicamente hice 2 preguntas en mi publicación. Uno está en el título, y creo que lo clavaste en tu respuesta y el otro es la última línea de mi publicación, por lo que creo que los puntos van a sbi.

    – BeeBand

    13 de agosto de 2010 a las 9:37


  • @BeeBand Jeje, está bien. Me alegro de haber proporcionado respuestas a algunas de sus preguntas.

    – Ígor Zevaka

    13 de agosto de 2010 a las 9:48


  • @Binary: No estoy seguro de su calendario, pero por aquí, después de diciembre viene enero. Eso es más o menos lo mismo que cuando incrementas std::numeric_limits<int>::max(). De todos modos, la pregunta no era por qué es así (“Lo que tiene sentido para mí…”), pero que hacer en su lugar (“¿Qué es un buen sustituto?”).

    – sbi

    13 de agosto de 2010 a las 9:52


Lanzamiento de ida y vuelta hacia/desde int es, por supuesto, la solución obvia, entonces deja en claro que entiende que la adición está ocurriendo “fuera” del enum:

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

  • Mmm. Sí, esa era mi otra opción, solo creo que todos esos actores hacen que el código se vea un poco desordenado.

    – BeeBand

    13 de agosto de 2010 a las 8:39

¿Por qué no almacenar? nextAvail como un int en cambio, si vas a hacer operaciones aritméticas en él?

Otra opción sería envolver la enumeración en su propio tipo y sobrecargar operator ++ para ello (que también podría envolver o algo por ejemplo).

Se supone semánticamente que una enumeración representa un conjunto de valores distintos relacionados.

Entonces podrías tener

enum Colour {RED, GREEN, BLUE};

Pero eso debería ser equivalente a:

enum Colour {GREEN, BLUE, RED};

El problema es que si incrementa una enumeración, esas representaciones no son las mismas. VERDE++ en el primer caso no es lo mismo que VERDE++ en el segundo.

Hacer que su programa dependa de la declaración de la enumeración es una receta para el desastre: los mantenedores pueden asumir que el orden de la enumeración no importa, introduciendo muchos errores silenciosos.

  • pero es posible asignar explícitamente los valores a las enumeraciones, por ejemplo enum Colour {RED = 0, GREEN = 1, BLUE = 2}. En ese caso el orden no importa.

    – Naveen

    13 de agosto de 2010 a las 8:35

  • Cierto, pero luego va más allá de lo que debería ser una enumeración y lo cruza como un conjunto de pares clave/valor.

    – PaulJWilliams

    13 de agosto de 2010 a las 8:37

  • no está claro lo que está sugiriendo cuando dice “eso debería ser equivalente”, ¿puede elaborar un poco?

    – BeeBand

    13 de agosto de 2010 a las 8:37

  • @BeeBand: cambiar el orden dentro de una enumeración no debería cambiar el comportamiento del código; pero en tu caso, lo hará.

    – egrunín

    13 de agosto de 2010 a las 8:40

  • Por supuesto. La primera declaración expresa el hecho de que hay tres colores, rojo, verde y azul. Eso es todo lo que dice. Pero el segundo dice lo mismo. Un mantenedor del código puede, perfectamente razonable, agregar un color, AMARILLO, entre VERDE y AZUL. Pero cualquier código que asumiera (implícita o explícitamente) que VERDE + 1 = AZUL se rompería silenciosamente. En resumen, las enumeraciones son para expresar conjuntos de valores que tienen un atributo común (en este caso, que son colores), en lugar de una relación entre ellos (que el verde viene antes que el azul, o después del rojo, etc.)

    – PaulJWilliams

    13 de agosto de 2010 a las 8:42

avatar de usuario
Vasavya Yagati

Muy simple:

nextDisponible = (StackID)(nextDisponible + 1);

  • pero es posible asignar explícitamente los valores a las enumeraciones, por ejemplo enum Colour {RED = 0, GREEN = 1, BLUE = 2}. En ese caso el orden no importa.

    – Naveen

    13 de agosto de 2010 a las 8:35

  • Cierto, pero luego va más allá de lo que debería ser una enumeración y lo cruza como un conjunto de pares clave/valor.

    – PaulJWilliams

    13 de agosto de 2010 a las 8:37

  • no está claro lo que está sugiriendo cuando dice “eso debería ser equivalente”, ¿puede elaborar un poco?

    – BeeBand

    13 de agosto de 2010 a las 8:37

  • @BeeBand: cambiar el orden dentro de una enumeración no debería cambiar el comportamiento del código; pero en tu caso, lo hará.

    – egrunín

    13 de agosto de 2010 a las 8:40

  • Por supuesto. La primera declaración expresa el hecho de que hay tres colores, rojo, verde y azul. Eso es todo lo que dice. Pero el segundo dice lo mismo. Un mantenedor del código puede, perfectamente razonable, agregar un color, AMARILLO, entre VERDE y AZUL. Pero cualquier código que asumiera (implícita o explícitamente) que VERDE + 1 = AZUL se rompería silenciosamente. En resumen, las enumeraciones son para expresar conjuntos de valores que tienen un atributo común (en este caso, que son colores), en lugar de una relación entre ellos (que el verde viene antes que el azul, o después del rojo, etc.)

    – PaulJWilliams

    13 de agosto de 2010 a las 8:42

Las enumeraciones van a ser de tipo int, para que puedas emitirlos. ¿Es esto lo que estás tratando de hacer?

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

Esto va a hacer que alguien se sienta muy confundido en el futuro, por supuesto.

Se me ocurre que estás usando un enum donde deberías estar usando consto incluso #define. enum es más apropiado cuando tienes arbitrario valores (donde el valor exacto no es significativo).

  • Creo que podrías tener razón re. constante Mi código asume que el valor exacto es significativo y, como usted (y otros carteles) han sugerido, rompe el significado previsto de una enumeración.

    – BeeBand

    13 de agosto de 2010 a las 8:54

  • las enumeraciones no siempre son de tipo int.

    – jchl

    20 de noviembre de 2019 a las 8:54

¿Ha sido útil esta solución?