tipados tipado sinonimo lenguajes fuertemente débilmente c++ c++11 strongly-typed-enum

c++ - sinonimo - lenguajes fuertemente y débilmente tipados



¿Cómo convertir automáticamente enum fuertemente tipado en int? (10)

#include <iostream> struct a { enum LOCAL_A { A1, A2 }; }; enum class b { B1, B2 }; int foo( int input ) { return input; } int main(void) { std::cout<<foo(a::A1)<<std::endl; std::cout<<foo(static_cast<int>(b::B2))<<std::endl; }

El a::LOCAL_A es lo que la enumeración fuertemente tipada está tratando de lograr, pero hay una pequeña diferencia: las enumeraciones normales se pueden convertir a tipo entero, mientras que las enumeraciones fuertemente tipadas no pueden hacerlo sin un molde.

Entonces, ¿hay alguna manera de convertir un valor enum fuertemente tipado en un tipo entero sin un molde? Si es así, ¿cómo?


Como han dicho otros, no se puede tener una conversión implícita, y eso es por diseño.

Si lo desea, puede evitar la necesidad de especificar el tipo subyacente en el elenco.

template <typename E> constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept { return static_cast<typename std::underlying_type<E>::type>(e); } std::cout << foo(to_underlying(b::B2)) << std::endl;


Como muchos dijeron, no hay forma de convertir automáticamente sin agregar gastos generales y demasiada complejidad, pero puedes reducir tu escritura un poco y hacer que se vea mejor usando lambdas si se usará algo de yeso un poco en un escenario. Eso agregaría un poco de llamada de encabezado de función, pero hará que el código sea más legible en comparación con las cadenas de transmisión estática largas como se puede ver a continuación. Esto puede no ser útil para todo el proyecto, sino solo para toda la clase.

#include <bitset> #include <vector> enum class Flags { ......, Total }; std::bitset<static_cast<unsigned int>(Total)> MaskVar; std::vector<Flags> NewFlags; ----------- auto scui = [](Flags a){return static_cast<unsigned int>(a); }; for (auto const& it : NewFlags) { switch (it) { case Flags::Horizontal: MaskVar.set(scui(Flags::Horizontal)); MaskVar.reset(scui(Flags::Vertical)); break; case Flags::Vertical: MaskVar.set(scui(Flags::Vertical)); MaskVar.reset(scui(Flags::Horizontal)); break; case Flags::LongText: MaskVar.set(scui(Flags::LongText)); MaskVar.reset(scui(Flags::ShorTText)); break; case Flags::ShorTText: MaskVar.set(scui(Flags::ShorTText)); MaskVar.reset(scui(Flags::LongText)); break; case Flags::ShowHeading: MaskVar.set(scui(Flags::ShowHeading)); MaskVar.reset(scui(Flags::NoShowHeading)); break; case Flags::NoShowHeading: MaskVar.set(scui(Flags::NoShowHeading)); MaskVar.reset(scui(Flags::ShowHeading)); break; default: break; } }


Enumeraciones fuertemente tipadas con el objetivo de resolver problemas múltiples y no solo problemas de alcance como usted mencionó en su pregunta:

  1. Proporcionar seguridad de tipo, eliminando así la conversión implícita a entero mediante promoción integral.
  2. Especifique los tipos subyacentes.
  3. Proporcione un buen alcance.

Por lo tanto, es imposible convertir implícitamente una enumeración fuertemente tipada en enteros, o incluso su tipo subyacente; esa es la idea. Por lo tanto, debe usar static_cast para que la conversión sea explícita.

Si su único problema es el alcance y realmente desea una promoción implícita a los enteros, entonces será mejor que utilice enum no fuertemente tipado con el alcance de la estructura en la que está declarado.

¡Espero eso ayude!


Espero que esto te ayude a ti o a alguien más

enum class EnumClass : int //set size for enum { Zero, One, Two, Three, Four }; union Union //This will allow us to convert { EnumClass ec; int i; }; int main() { using namespace std; //convert from strongly typed enum to int Union un2; un2.ec = EnumClass::Three; cout << "un2.i = " << un2.i << endl; //convert from int to strongly typed enum Union un; un.i = 0; if(un.ec == EnumClass::Zero) cout << "True" << endl; return 0; }


Esto parece imposible con la enum class nativa, pero probablemente puedas burlar una enum class con una class :

En este caso,

enum class b { B1, B2 };

sería equivalente a:

class b { private: int underlying; public: static constexpr int B1 = 0; static constexpr int B2 = 1; b(int v) : underlying(v) {} operator int() { return underlying; } };

Esto es principalmente equivalente a la enum class original. Puede devolver b::B1 directamente en una función con el tipo de retorno b . Puedes switch case con él, etc.

Y en el espíritu de este ejemplo, puede usar plantillas (posiblemente junto con otras cosas) para generalizar y simular cualquier objeto posible definido por la sintaxis de la enum class .


La razón de la ausencia de conversión implícita (por diseño) se dio en otras respuestas.

Yo personalmente uso el operator+ unario operator+ para la conversión de clases enum a su tipo subyacente:

template <typename T> constexpr auto operator+(T e) noexcept -> std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>> { return static_cast<std::underlying_type_t<T>>(e); }

Lo cual da bastante "sobrecarga de tipeo":

std::cout << foo(+b::B2) << std::endl;

Donde realmente utilizo una macro para crear enumeraciones y las funciones del operador en una sola toma.

#define UNSIGNED_ENUM_CLASS(name, ...) enum class name : unsigned { __VA_ARGS__ };/ inline constexpr unsigned operator+ (name const val) { return static_cast<unsigned>(val); }


La respuesta corta es que no se puede, como se señala en las publicaciones anteriores. Pero en mi caso, simplemente no quería saturar el espacio de nombres, pero aún tenía conversiones implícitas, así que lo hice:

#include <iostream> using namespace std; namespace Foo { enum { bar, baz }; } int main() { cout << Foo::bar << endl; // 0 cout << Foo::baz << endl; // 1 return 0; }

El tipo de espaciado de nombres agrega una capa de seguridad de tipo, mientras que no tengo que establecer ningún valor estático en el tipo subyacente.


No. No hay una forma natural .

De hecho, una de las motivaciones detrás de tener una enum class fuertemente enum class en C ++ 11 es evitar su conversión silenciosa a int .


Una versión de C ++ 14 de la respuesta provista por R. Martinho Fernandes sería:

#include <type_traits> template <typename E> constexpr auto to_underlying(E e) noexcept { return static_cast<std::underlying_type_t<E>>(e); }

Al igual que con la respuesta anterior, esto funcionará con cualquier tipo de enumeración y tipo subyacente. He agregado la palabra clave noexcept ya que nunca lanzará una excepción.

Actualizar
Esto también aparece en Effective Modern C ++ por Scott Meyers . Vea el ítem 10 (se detalla en las páginas finales del ítem dentro de mi copia del libro).


#include <cstdlib> #include <cstdio> #include <cstdint> #include <type_traits> namespace utils { namespace details { template< typename E > using enable_enum_t = typename std::enable_if< std::is_enum<E>::value, typename std::underlying_type<E>::type >::type; } // namespace details template< typename E > constexpr inline details::enable_enum_t<E> underlying_value( E e )noexcept { return static_cast< typename std::underlying_type<E>::type >( e ); } template< typename E , typename T> constexpr inline typename std::enable_if< std::is_enum<E>::value && std::is_integral<T>::value, E >::type to_enum( T value ) noexcept { return static_cast<E>( value ); } } // namespace utils int main() { enum class E{ a = 1, b = 3, c = 5 }; constexpr auto a = utils::underlying_value(E::a); constexpr E b = utils::to_enum<E>(5); constexpr auto bv = utils::underlying_value(b); printf("a = %d, b = %d", a,bv); return 0; }