2011-11-17 12 views
10

Me gustaría que el compilador diera una advertencia como:¿Debería el compilador dar una advertencia si las etiquetas enum no coinciden con el tipo?

"El plátano no es un color".

Entiendo que en el contexto de una declaración de cambio las etiquetas se promueven a int y el compilador está contento con 0 y no le importa si es "Verde" o "Banana".

Estaba esperando -Wconversion para GCC haría el truco.

enum Color 
    { 
    Green = 0 
    }; 

enum Fruit 
    { 
    Banana = 0 
    }; 

int main() 
{ 
    Color c = Green; 
    switch (c) 
    { 
    case Banana: 
     std::cerr << "Banana" << std::endl; 
     break; 
    } 
    return 0; 
} 
+0

¿Qué compilador? – FailedDev

+3

No hay un diagnóstico requerido en 6.4.2 de C++ 11, si eso es lo que quiere decir con "¿debería el compilador dar una advertencia?". Entonces, la respuesta a la pregunta que hizo fue "no", pero tal vez la pregunta que desea hacer es "¿hay algún compilador en el que pueda activar tal advertencia y, de ser así, cómo?" ;-) –

+4

Ah, y "las etiquetas se promocionan a int" - no es tan simple. Las etiquetas se convierten al tipo promocionado de 'c', que es al menos' int', y 'int' es suficiente para la enumeración que definió, pero podría ser de otro tipo, como' unsigned int' o 'long long '. –

Respuesta

17

fuertemente tipado enumeraciones:

C++ 11 introduce mecanografiadas fuertemente enum s, utilizando enum class:

#include <iostream> 

enum class Color 
    { 
    Green = 0 
    }; 

enum class Fruit 
    { 
    Banana = 0 
    }; 


int main() { 
    Color c = Color::Green; 
    switch (c) 
    { 
    case Fruit::Banana: 
     std::cerr << "Banana" << std::endl; 
     break; 
    } 
    return 0; 

} 

Este código se producirá un error exactamente como usted esperaba:

test.cc:18:17: error: could not convert '(Fruit)0' from 'Fruit' to 'Color'

Nota: enum class no causa Green y Banana estar en el espacio de nombres que encierra más, así que usted tiene que escribir explícitamente Color:: y Fruit:: ahora, pero usted también obtener el typesafety.


Los problemas de advertencia en C++ 03

No creo advertencia sobre esto en C++ 03 tendría mucho sentido, sería básicamente convertido en ruido.

Las personas usan enum s como constantes de tiempo de compilación con bastante frecuencia, incluso para cosas como campos de bits. Para que la advertencia sea significativa, debe capturar cosas como enum { foo=0xf }; int c = foo; y muchas bases de código están diseminadas con int/enum conversiones. (Permitir esto frustraría el punto de cualquier verificación de tipo más fuerte).

Peor aún, aunque se enum s utilizan en casi cualquier tipo de contexto de programación meta, donde anónimas enum s no sólo se utilizan libremente intercambiable con int tipos de forma regular:

template <int I> 
struct is_odd { 
    enum { value = !(I % 2) }; 
}; 

template <int I> 
struct foo { 
    static void bar() { /* I is true */ } 
}; 

template <> 
struct foo<0> { 
    static void bar() { /* I is false */ } 
}; 

int main() { 
    foo<is_odd<201>::value>::bar(); 
    int i = is_odd<200>::value; 
} 

pero son también se utiliza de forma recursiva como almacenamiento local:

template <int N> 
struct factorial { 
    enum { 
     // This enum is *not* compatible with the one in N-1 
     value = N * factorial<N - 1>::value 
    }; 
}; 

template <> 
struct factorial<0> { 
    enum { value = 1 }; 
}; 

que es una parte de la razón por enum class fue requerido con el fin de introducir una forma de no separación del complemento g type-safety sobre el estado actual de enum s en C++. Habría tantas advertencias del código existente que una advertencia sería inútil debido a cosas como esta.

Incluso en el relativamente sencillo ejemplo instrucción switch que mostró, algo como esto es legal:

#include <iostream> 
enum Color { Green = 0x1, Red = 0x2 }; 
enum Fruit { Banana = 0x3 }; 

int main() { 
    int v = Green|Red; 
    Color c = Color(v); 
    switch (c) { 
    case Banana: 
    std::cerr << "Banana" << std::endl; 
    break; 
    } 
    return 0; 
} 

Aunque esto es legal aquí no es enormemente significativas, pero las cosas similares que se usan con bastante regularidad y de manera significativa en el " bit-twiddling "Código C todavía. El punto de este ejemplo es que al permitir una int < ->enum conversión en cualquier lugar significa que ser estricto sobre el tipo de enum más tarde se vuelve sin sentido. En el caso general, no puede detectar si este tipo de conversión ha sucedido (podría haber estado en una unidad de traducción diferente).

enum class es, de lejos, la forma más sencilla de introducir este rigor de manera limpia y sin efectos adversos en el código existente.

+0

Creo que ha agregado algunos puntos válidos aquí, sin embargo, no veo por qué una advertencia en el contexto de una declaración de cambio no sería útil. –

+0

@ EddyPronk - He hecho otra edición, que espero que muestre por qué el solo hecho de permitir conversiones int-> enum hace que las advertencias de este tipo sean inútiles. – Flexo

+0

Me gusta 'enum class', pero pasarán años antes de que pueda usar las características de C++ 11 en la vida real. Agregaste más sobre conversiones, que está relacionado, pero no sobre el caso específico sobre el que estoy preguntando. De nuevo, en el contexto específico de una declaración de cambio, tendría sentido advertir sobre el hecho de que activamos el tipo Color y tenemos una etiqueta de caso de tipo Fruta. Debería haber suficiente contexto para advertir acerca de algo sospechoso aquí. –

6

En C++ 11 (el nuevo estándar de C++) que puede utilizar para crear un enum class inflexible de tipos de enumeración. Vea el Wikipedia article on C++11.

Ejemplo:

enum class Color { Green }; 
enum class Fruit { Banana }; 

// Put your main here - it would now fail 
+0

¿Funcionaría el interruptor incluso ahora? Supongo que no. –

+0

No, no importa, el "tipo de enumeración" está explícitamente permitido como un objetivo de conversión. :) –

Cuestiones relacionadas