Directrices básicas de C++:reglas para enumeraciones

Directrices básicas de C++:reglas para enumeraciones

La sección de enumeraciones tiene ocho reglas. Desde C++ 11, tenemos enumeraciones de ámbito que superan muchos de los inconvenientes de las enumeraciones clásicas.

Las enumeraciones son conjuntos de valores enteros, que se comportan como un tipo. Aquí está el resumen de las reglas:

  • Enum.1:Preferir enumeraciones sobre macros
  • Enum.2:use enumeraciones para representar conjuntos de constantes nombradas relacionadas
  • Enum.3:Preferir enum class es sobre "simple" enum s
  • Enum.4:Definir operaciones en enumeraciones para un uso seguro y simple
  • Enum.5:No use ALL_CAPS para enumeradores
  • Enum.6:Evite las enumeraciones sin nombre
  • Enum.7:Especifique el tipo subyacente de una enumeración solo cuando sea necesario
  • Enum.8:Especifique los valores del enumerador solo cuando sea necesario

Como mencioné al comienzo de esta publicación:las enumeraciones clásicas tienen muchos inconvenientes. Permítanme comparar explícitamente las enumeraciones clásicas (sin ámbito) y las enumeraciones con ámbito (a veces llamadas enumeraciones fuertemente tipadas), porque esta importante comparación no se describe explícitamente en las reglas.

He aquí una enumeración clásica:

enum Colour{
 red,
 blue,
 green
};

Estos son los inconvenientes de las enumeraciones clásicas:

  • Los enumeradores no tienen alcance
  • Los enumeradores se convierten implícitamente a implícitamente a int
  • Los enumeradores contaminan el espacio de nombres global
  • El tipo del enumerador no está definido. Solo tiene que ser lo suficientemente grande como para contener el enumerador.

Al usar la palabra clave class o struct, la enumeración clásica se convierte en una enumeración con ámbito (clase enum):

enum class ColourScoped{
 red,
 blue,
 green
};

Ahora, debe usar el operador de alcance para acceder a los enumeradores:ColourScoped::red. ColourScoped::red no se convertirá implícitamente a int y, por lo tanto, no contaminará el espacio de nombres global. Además, el tipo subyacente es por defecto int.

Después de proporcionar la información de fondo, podemos saltar directamente a las reglas.

Enumeración.1:Preferir enumeraciones sobre macros

Las macros no respetan un alcance y no tienen tipo. Esto significa que puede anular una macro establecida previamente que especifica un color.

// webcolors.h 
#define RED 0xFF0000

// productinfo.h
#define RED 0

int webcolor = RED; // should be 0xFF0000

Con ColourScoped esto no sucederá porque debe usar el operador de alcance:ColourScoped webcolour =ColourScoped::red;

Esta regla es bastante obvia porque los enumeradores son un conjunto de números enteros que crean un tipo de tipo.

Enum.3:Preferir enum class es sobre “simple” enum s

Los enumeradores de una enumeración con ámbito (clase de enumeración) no se convertirán automáticamente a int. Tienes que acceder a ellos con el operador de ámbito.

// scopedEnum.cpp

#include <iostream>

enum class ColourScoped{
 red,
 blue,
 green
};

void useMe(ColourScoped color){

 switch(color){
 case ColourScoped::red:
 std::cout << "ColourScoped::red" << std::endl;
 break;
 case ColourScoped::blue:
 std::cout << "ColourScoped::blue" << std::endl;
 break;
 case ColourScoped::green:
 std::cout << "ColourScoped::green" << std::endl;
 break;
 }
}

int main(){

 std::cout << static_cast<int>(ColourScoped::red) << std::endl; // 0
 std::cout << static_cast<int>(ColourScoped::red) << std::endl; // 0

 std::cout << std::endl;

 ColourScoped colour{ColourScoped::red};
 useMe(colour); // ColourScoped::red

}

Enumeración.4:Definir operaciones en enumeraciones para un uso seguro y sencillo

Las reglas definen un día de enumeración que admite la operación de incremento.

enum Day { mon, tue, wed, thu, fri, sat, sun };

Day& operator++(Day& d)
{
 return d = (d == Day::sun) ? Day::mon : static_cast<Day>(static_cast<int>(d)+1);
}

Day today = Day::sat;
Day tomorrow = ++today;

El static_cast es necesario en este ejemplo porque aplicar el operador de incremento dentro del operador de incremento causaría una recursividad infinita:

Day& operator++(Day& d)
{
 return d = (d == Day::sun) ? Day::mon : Day{++d}; // error
}

Enumerator.5:No use ALL_CAPS para enumeradores

Si usa ALL_CAPS para los enumeradores, es posible que tenga un conflicto con las macros porque normalmente se escriben en ALL_CAPS.

#define RED 0xFF0000

enum class ColourScoped{ RED }; // error

Enumeración.6:Evitar enumeraciones sin nombre

Si no puede encontrar un nombre para las enumeraciones, es posible que las enumeraciones no estén relacionadas. En este caso, debe usar un valor constexpr.

// bad
enum { red = 0xFF0000, scale = 4, is_signed = 1 };

// good
constexpr int red = 0xFF0000;
constexpr short scale = 4;
constexpr bool is_signed = true;

Enum.7:Especifique el tipo subyacente de una enumeración solo cuando sea necesario

Desde C++11, puede especificar el tipo subyacente de la enumeración y ahorrar memoria. De forma predeterminada, el tipo de una enumeración con ámbito es int y, por lo tanto, puede reenviar declarar una enumeración.

// typeEnum.cpp

#include <iostream>

enum class Colour1{
 red,
 blue,
 green
};
 
enum struct Colour2: char {
 red,
 blue,
 green
};

int main(){

 std::cout << sizeof(Colour1) << std::endl; // 4
 std::cout << sizeof(Colour2) << std::endl; // 1

}

Enumerator.8:Especifique los valores del enumerador solo cuando sea necesario

Al especificar los valores del enumerador, puede suceder que establezca un valor dos veces. La siguiente enumeración Col2 tiene este problema.

enum class Col1 { red, yellow, blue };
enum class Col2 { red = 1, yellow = 2, blue = 2 }; // typo
enum class Month { jan = 1, feb, mar, apr, may, jun,
 jul, august, sep, oct, nov, dec }; // starting with 1 is conventional

¿Qué sigue?

Lo hice relativamente corto en este post. La metarregla que debe tener en cuenta es:use enumeraciones de alcance .

La siguiente sección de las directrices básicas de C++ trata de unas 35 reglas para la gestión de recursos. Esto significa que en la próxima publicación nos sumergiremos en el corazón de C++.