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.
¿Qué compilador? – FailedDev
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?" ;-) –
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 '. –