Tengo un montón de tipos de enumeración en algunos archivos de encabezado de biblioteca que estoy usando, y quiero tener una forma de convertir valores de enumeración en cadenas de usuario, y viceversa.
RTTI no lo hará por mí, porque las 'cadenas de usuario' deben ser un poco más legibles que las enumeraciones.
Una solución de fuerza bruta sería un montón de funciones como esta, pero creo que eso es demasiado parecido a C.
enum MyEnum {VAL1, VAL2,VAL3};
String getStringFromEnum(MyEnum e)
{
switch e
{
case VAL1: return "Value 1";
case VAL2: return "Value 2";
case VAL1: return "Value 3";
default: throw Exception("Bad MyEnum");
}
}
Tengo el presentimiento de que hay una solución elegante con plantillas, pero todavía no puedo entenderlo.
ACTUALIZACIÓN: Gracias por las sugerencias, debería haber dejado en claro que las enumeraciones están definidas en un encabezado de biblioteca de terceros, por lo que no quiero tener que cambiar la definición de ellas.
Mi instinto ahora es evitar las plantillas y hacer algo como esto:
char * MyGetValue(int v, char *tmp); // implementation is trivial
#define ENUM_MAP(type, strings) char * getStringValue(const type &T) \
{ \
return MyGetValue((int)T, strings); \
}
; enum eee {AA,BB,CC}; - exists in library header file
; enum fff {DD,GG,HH};
ENUM_MAP(eee,"AA|BB|CC")
ENUM_MAP(fff,"DD|GG|HH")
// To use...
eee e;
fff f;
std::cout<< getStringValue(e);
std::cout<< getStringValue(f);
Respuestas:
Si desea que los nombres de la enumeración sean cadenas, consulte esta publicación . De lo contrario,
std::map<MyEnum, char const*>
funcionará bien. (No tiene sentido copiar sus literales de cadena a std :: cadenas en el mapa)Para obtener más azúcar sintáctico, aquí se explica cómo escribir una clase map_init. El objetivo es permitir
La función
template <typename T> map_init(T&)
devuelve amap_init_helper<T>
.map_init_helper<T>
almacena un T & y define lo trivialmap_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)
. (Regresar*this
deoperator()
permite el encadenamiento deoperator()
, comooperator<<
enstd::ostream
s)Dado que la función y la clase de ayuda tienen plantilla, puede usarlas para cualquier mapa o estructura similar a un mapa. Es decir, también puede agregar entradas a
std::unordered_map
Si no le gusta escribir estos ayudantes, boost :: assign ofrece la misma funcionalidad lista para usar.
fuente
La solución de MSalters es buena pero básicamente se vuelve a implementar
boost::assign::map_list_of
. Si tiene impulso, puede usarlo directamente:fuente
eee
en su caso.error: template declaration of 'const boost::unordered::unordered_map<T, const char*> enumToString'
.Genere automáticamente un formulario a partir de otro.
Fuente:
Generado:
Si los valores de enumeración son grandes, entonces un formulario generado podría usar unordered_map <> o plantillas como lo sugiere Constantin.
Fuente:
Generado:
Ejemplo:
fuente
Recuerdo haber respondido esto en otra parte de StackOverflow. Repitiéndolo aquí. Básicamente es una solución basada en macros variadic y es bastante fácil de usar:
Para usarlo en su código, simplemente haga:
fuente
Sugiero que una combinación del uso de X-macros sea la mejor solución y las siguientes funciones de plantilla:
Para pedir prestado a marcinkoziukmyopenidcom y extendido
colour.def
fuente
Utilizo esta solución que reproduzco a continuación:
fuente
Si desea obtener representaciones de cadenas de
MyEnum
variables , las plantillas no lo cortarán. La plantilla se puede especializar en valores integrales conocidos en tiempo de compilación.Sin embargo, si eso es lo que quiere, intente:
Esto es detallado, pero detectará errores como el que cometió en cuestión:
case VAL1
está duplicado.fuente
He pasado más tiempo investigando este tema del que me gustaría admitir. Afortunadamente, existen excelentes soluciones de código abierto en la naturaleza.
Estos son dos grandes enfoques, incluso si no son lo suficientemente conocidos (todavía),
sabio_enum
Mejores enumeraciones
fuente
Me sentiría tentado a tener un mapa m e incrustarlo en la enumeración.
configuración con m [MyEnum.VAL1] = "Valor 1";
y todo está hecho.
fuente
He requerido esta funcionalidad varias veces para depurar / analizar código de otros. Para esto, escribí un script en Perl que genera una clase con varios
toString
métodos sobrecargados . CadatoString
método toma unEnum
como argumento y devuelveconst char*
.Por supuesto, el script no analiza C ++ para las enumeraciones en sí, sino que usa ctags para generar tablas de símbolos.
El script de Perl está aquí: http://heinitz-it.de/download/enum2string/enum2string.pl.html
fuente
Tus respuestas me inspiraron a escribir algunas macros yo mismo. Mis requisitos fueron los siguientes:
solo escriba cada valor de la enumeración una vez, por lo que no hay listas dobles para mantener
no guarde los valores de enumeración en un archivo separado que luego se #incluye, para que pueda escribirlo donde quiera
no reemplace la enumeración en sí, todavía quiero tener definido el tipo de enumeración, pero además quiero poder asignar cada nombre de enumeración a la cadena correspondiente (para no afectar el código heredado)
la búsqueda debe ser rápida, por lo que preferiblemente sin cambiar mayúsculas y minúsculas, para esas enormes enumeraciones
Este código crea una enumeración clásica con algunos valores. Además, crea como std :: map que asigna cada valor de enumeración a su nombre (es decir, mapa [E_SUNDAY] = "E_SUNDAY", etc.)
Ok, aquí está el código ahora:
EnumUtilsImpl.h :
EnumUtils.h // este es el archivo que desea incluir siempre que necesite hacer esto, usará las macros de él:
MyProjectCodeFile.h // este es un ejemplo de cómo usarlo para crear una enumeración personalizada:
Salud.
fuente
Aquí hay un intento de obtener << y >> operadores de flujo en enumeración automáticamente con un comando de macro de una línea solamente ...
Definiciones:
Uso:
Sin embargo, no estoy seguro de las limitaciones de este esquema ... ¡los comentarios son bienvenidos!
fuente
en el encabezado:
en el archivo .cpp:
Advertencia: no maneje un índice de matriz incorrecto. :) Pero puede agregar fácilmente una función para verificar la enumeración antes de obtener la cadena de la matriz.
fuente
Solo quería mostrar esta posible solución elegante usando macros. Esto no resuelve el problema, pero creo que es una buena manera de repensar el problema.
---- EDITAR ----
Después de algunas investigaciones en Internet y algunos experimentos propios, llegué a la siguiente solución:
Solo quería publicarlo, tal vez alguien pueda encontrar útil esta solución. No hay necesidad de clases de plantillas, no se necesita c ++ 11 y no se necesita impulso, por lo que esto también podría usarse para C.
---- EDIT2 ----
la tabla de información puede producir algunos problemas al usar más de 2 enumeraciones (problema del compilador). La siguiente solución alternativa funcionó:
fuente
Arriba está mi solución simple. Uno de sus beneficios es el 'NUM' que controla el tamaño de la matriz de mensajes, también evita el acceso fuera de los límites (si lo usa con prudencia).
También puede definir una función para obtener la cadena:
Además de mi solución, encontré la siguiente bastante interesante. En general, resolvió el problema de sincronización del anterior.
Diapositivas aquí: http://www.slideshare.net/arunksaha/touchless-enum-tostring-28684724
Código aquí: https://github.com/arunksaha/enum_to_string
fuente
Sé que llego tarde a la fiesta, pero para todos los que vengan a visitar esta página, pueden probar esto, es más fácil que todo lo que hay allí y tiene más sentido:
fuente
Recientemente tuve el mismo problema con una biblioteca de proveedor (Fincad). Afortunadamente, el proveedor proporcionó documentación xml para todas las enumeraciones. Terminé generando un mapa para cada tipo de enumeración y proporcionando una función de búsqueda para cada enumeración. Esta técnica también le permite interceptar una búsqueda fuera del rango de la enumeración.
Estoy seguro de que swig podría hacer algo similar por usted, pero me complace proporcionar las utilidades de generación de código que están escritas en ruby.
Aquí hay una muestra del código:
Parece que quiere ir al revés (enumeración a cadena, en lugar de cadena a enumeración), pero esto debería ser trivial para revertir.
-Pizca
fuente
Vea si la siguiente sintaxis le conviene:
Si es así, es posible que desee consultar este artículo:
http://www.gamedev.net/reference/snippets/features/cppstringizing/
fuente
este viejo lío correcto es mi esfuerzo basado en fragmentos de SO. For_each tendría que expandirse para admitir más de 20 valores de enumeración. Lo probé en visual studio 2019, clang y gcc. c ++ 11
que produce el siguiente código
Es una pena los aros que tienes que saltar con el preprocesador para hacer esto en uno de los lenguajes de programación más utilizados en el mundo ...
fuente
Al usar inicializadores de matriz designados, su matriz de cadenas es independiente del orden de los elementos en la enumeración:
fuente