Un enum X : int
(C #) o enum class X : int
(C ++ 11) es un tipo que tiene un campo interno oculto de int
que puede contener cualquier valor. Además, una serie de constantes predefinidas de X
se definen en la enumeración. Es posible convertir la enumeración a su valor entero y viceversa. Todo esto es cierto tanto en C # como en C ++ 11.
En C # las enumeraciones no solo se usan para mantener valores individuales, sino también para mantener combinaciones de indicadores a nivel de bits, según recomendación de Microsoft . Tales enumeraciones están (generalmente, pero no necesariamente) decoradas con el atributo [Flags]
. Para facilitar la vida de los desarrolladores, los operadores bitwise (OR, AND, etc ...) están sobrecargados para que pueda hacer algo como esto (C #):
void M(NumericType flags);
M(NumericType.Sign | NumericType.ZeroPadding);
Soy un desarrollador de C # experimentado, pero he estado programando C ++ solo por un par de días, y no soy conocido con las convenciones de C ++. Tengo la intención de usar una enumeración de C ++ 11 exactamente de la misma manera que solía hacerlo en C #. En C ++ 11, los operadores bitwise en enumerados de ámbito no están sobrecargados, por lo que quería sobrecargarlos .
Esto solicitó un debate, y las opiniones parecen variar entre tres opciones:
-
Una variable del tipo de enumeración se usa para mantener el campo de bits, similar a C #:
void M(NumericType flags); // With operator overloading: M(NumericType::Sign | NumericType::ZeroPadding); // Without operator overloading: M(static_cast<NumericType>(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding)));
Pero esto contrarrestaría la filosofía de enumeración fuertemente tipada de las enumeraciones con alcance de C ++ 11.
-
Use un entero liso si desea almacenar una combinación de enumeraciones a nivel de bits:
void M(int flags); M(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding));
Pero esto reduciría todo a un
int
, dejándote sin una pista sobre qué tipo se supone que debes poner en el método. -
Escriba una clase separada que sobrecargue a los operadores y mantenga las banderas bitwise en un campo entero oculto:
class NumericTypeFlags { unsigned flags_; public: NumericTypeFlags () : flags_(0) {} NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {} //...define BITWISE test/set operations }; void M(NumericTypeFlags flags); M(NumericType::Sign | NumericType::ZeroPadding);
( código completo por user315052 )
Pero entonces no tiene IntelliSense o cualquier otro soporte para sugerirle los posibles valores.
Sé que esto es una pregunta subjetiva , pero: ¿Qué ¿Qué enfoque debo usar? ¿Qué enfoque, si lo hay, es el más reconocido en C ++? ¿Qué enfoque utiliza cuando trata con los campos de bits y why?
Por supuesto, dado que los tres enfoques funcionan, busco razones objetivas y técnicas, convenciones generalmente aceptadas y no simplemente preferencias personales.
Por ejemplo, debido a mi fondo de C # tiendo a ir con el enfoque 1 en C ++. Esto tiene el beneficio adicional de que mi entorno de desarrollo puede sugerirme los posibles valores, y con los operadores de enumeración sobrecargados, esto es fácil de escribir y entender, y bastante limpio. Y la firma del método muestra claramente qué tipo de valor espera. Pero la mayoría de las personas aquí no están de acuerdo conmigo, probablemente por una buena razón.