Eu tenho um monte de tipos de enum em alguns arquivos de cabeçalho de biblioteca que estou usando e quero ter uma maneira de converter valores de enum em strings de usuário - e vice-versa.
O RTTI não fará isso para mim, porque as 'strings do usuário' precisam ser um pouco mais legíveis do que as enumerações.
Uma solução de força bruta seria um monte de funções como essa, mas acho que é um pouco parecido com 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");
}
}
Tenho a sensação de que existe uma solução elegante usando modelos, mas ainda não consigo entendê-la.
ATUALIZAÇÃO: obrigado pelas sugestões - eu deveria ter deixado claro que os enums são definidos em um cabeçalho de biblioteca de terceiros, então não quero ter que mudar a definição deles.
Minha intuição agora é evitar modelos e fazer algo assim:
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);
Respostas:
Se você quiser que o enum se nomeie como strings, consulte esta postagem . Caso contrário, um
std::map<MyEnum, char const*>
funcionará bem. (Não adianta copiar seus literais de string para std :: strings no mapa)Para obter mais açúcar sintático, veja como escrever uma classe map_init. O objetivo é permitir
A função
template <typename T> map_init(T&)
retorna ummap_init_helper<T>
.map_init_helper<T>
armazena um T & e define o trivialmap_init_helper& operator()(typename T::key_type const&, typename T::value_type const&)
. (Retornar*this
deoperator()
permite o encadeamento deoperator()
, comooperator<<
emstd::ostream
s)Como a função e a classe auxiliar são modeladas, você pode usá-las para qualquer mapa ou estrutura semelhante a um mapa. Ou seja, também pode adicionar entradas a
std::unordered_map
Se você não gosta de escrever esses helpers, boost :: assign oferece a mesma funcionalidade fora da caixa.
fonte
A solução MSalters é boa, mas basicamente reimplementada
boost::assign::map_list_of
. Se você tiver impulso, pode usá-lo diretamente:fonte
eee
no seu caso.error: template declaration of 'const boost::unordered::unordered_map<T, const char*> enumToString'
.Gere automaticamente um formulário a partir de outro.
Fonte:
Gerado:
Se os valores enum forem grandes, um formulário gerado pode usar unordered_map <> ou modelos conforme sugerido por Constantin.
Fonte:
Gerado:
Exemplo:
fonte
Lembro-me de ter respondido isso em outro lugar no StackOverflow. Repetindo aqui. Basicamente, é uma solução baseada em macros variáveis e é muito fácil de usar:
Para usá-lo em seu código, basta fazer:
fonte
Sugiro que uma combinação de macros X são a melhor solução e as seguintes funções de modelo:
Para pedir emprestado marcinkoziukmyopenidcom e estendido
colour.def
fonte
Eu uso esta solução que reproduzo abaixo:
fonte
Se você deseja obter representações de strings de
MyEnum
variáveis , os modelos não vão funcionar. O modelo pode ser especializado em valores integrais conhecidos em tempo de compilação.No entanto, se é isso que você deseja, tente:
Isso é detalhado, mas detectará erros como o que você cometeu - o seu
case VAL1
está duplicado.fonte
Passei mais tempo pesquisando esse tópico que gostaria de admitir. Felizmente, existem ótimas soluções de código aberto à solta.
Estas são duas grandes abordagens, mesmo que não sejam bem conhecidas o suficiente (ainda),
sábio_enum
Melhores Enums
fonte
Eu ficaria tentado a ter um mapa m - e embuti-lo no enum.
configurar com m [MyEnum.VAL1] = "Valor 1";
e tudo está feito.
fonte
Eu exigi essa funcionalidade várias vezes para depurar / analisar código de outros. Para isso, escrevi um script Perl que gera uma classe com vários
toString
métodos sobrecarregados . CadatoString
método recebe umEnum
como argumento e retornaconst char*
.Obviamente, o script não analisa C ++ para enums em si, mas usa ctags para gerar a tabela de símbolos.
O script Perl está aqui: http://heinitz-it.de/download/enum2string/enum2string.pl.html
fonte
Suas respostas me inspiraram a escrever algumas macros sozinho. Meus requisitos eram os seguintes:
escreva cada valor do enum apenas uma vez, então não há listas duplas para manter
não mantenha os valores enum em um arquivo separado que será #incluído posteriormente, para que eu possa escrever onde quiser
não substitua o enum em si, ainda quero ter o tipo de enum definido, mas, além disso, quero ser capaz de mapear cada nome de enum para a string correspondente (para não afetar o código legado)
a pesquisa deve ser rápida, de preferência sem caixa de troca, para aqueles enormes enums
Este código cria um enum clássico com alguns valores. Além disso, ele cria como std :: map que mapeia cada valor enum para seu nome (ou seja, map [E_SUNDAY] = "E_SUNDAY", etc.)
Ok, aqui está o código agora:
EnumUtilsImpl.h :
EnumUtils.h // este é o arquivo que você deseja incluir sempre que precisar fazer isso, você usará as macros dele:
MyProjectCodeFile.h // este é um exemplo de como usá-lo para criar um enum personalizado:
Felicidades.
fonte
Aqui está uma tentativa de obter operadores de fluxo << e >> no enum automaticamente com um comando de macro de uma linha apenas ...
Definições:
Uso:
Não tenho certeza sobre as limitações deste esquema ... comentários são bem-vindos!
fonte
no cabeçalho:
no arquivo .cpp:
Advertência: não lide com índices de array ruins. :) Mas você pode adicionar facilmente uma função para verificar o enum antes de obter a string do array.
fonte
Eu só queria mostrar essa possível solução elegante usando macros. Isso não resolve o problema, mas acho que é uma boa maneira de repensar o problema.
---- EDITAR ----
Depois de algumas pesquisas na Internet e algumas experiências próprias, cheguei à seguinte solução:
Eu só queria postar talvez alguém possa achar esta solução útil. Não há necessidade de classes de modelos, não há necessidade de c ++ 11 e nem de aumento, então isso também pode ser usado para C.
---- EDIT2 ----
a tabela de informações pode produzir alguns problemas ao usar mais de 2 enums (problema do compilador). A seguinte solução alternativa funcionou:
fonte
Acima está minha solução simples. Um benefício disso é o 'NUM' que controla o tamanho do array da mensagem, ele também impede o acesso fora do limite (se você usá-lo com sabedoria).
Você também pode definir uma função para obter a string:
Na sequência da minha solução, achei a seguinte bastante interessante. Geralmente resolvia o problema de sincronização do acima.
Slides aqui: http://www.slideshare.net/arunksaha/touchless-enum-tostring-28684724
Codifique aqui: https://github.com/arunksaha/enum_to_string
fonte
Sei que estou atrasado para a festa, mas para todos os que vierem visitar esta página, você poderia tentar isso, é mais fácil do que tudo lá e faz mais sentido:
fonte
Recentemente, tive o mesmo problema com uma biblioteca de fornecedores (Fincad). Felizmente, o fornecedor forneceu documentação xml para todos os enums. Acabei gerando um mapa para cada tipo de enum e fornecendo uma função de pesquisa para cada enum. Essa técnica também permite interceptar uma pesquisa fora do intervalo do enum.
Tenho certeza que o swig poderia fazer algo semelhante por você, mas estou feliz em fornecer os utilitários de geração de código que são escritos em ruby.
Aqui está um exemplo do código:
Parece que você quer seguir o outro caminho (enum para string, em vez de string para enum), mas isso deve ser trivial para reverter.
-Whit
fonte
Veja se a seguinte sintaxe se adapta a você:
Em caso afirmativo, você pode querer verificar este artigo:
http://www.gamedev.net/reference/snippets/features/cppstringizing/
fonte
esta velha bagunça é meu esforço baseado em bits e peças do SO. O for_each teria que ser expandido para suportar mais de 20 valores enum. Testado no Visual Studio 2019, clang e gcc. c ++ 11
que produz o seguinte código
É uma pena os obstáculos que você tem que pular com o pré-processador para fazer isso em uma das linguagens de programação mais usadas no mundo ...
fonte
Ao usar inicializadores de matriz designados, sua matriz de string é independente da ordem dos elementos no enum:
fonte