Suponha que tenhamos algumas enumerações nomeadas:
enum MyEnum {
FOO,
BAR = 0x50
};
O que eu pesquisei no Google é um script (qualquer idioma) que varre todos os cabeçalhos do meu projeto e gera um cabeçalho com uma função por enumeração.
char* enum_to_string(MyEnum t);
E uma implementação com algo como isto:
char* enum_to_string(MyEnum t){
switch(t){
case FOO:
return "FOO";
case BAR:
return "BAR";
default:
return "INVALID ENUM";
}
}
A pegadinha é realmente com enumerações de tipo digitado e enumerações de estilo C sem nome. Alguém sabe alguma coisa para isso?
EDIT: A solução não deve modificar minha fonte, exceto para as funções geradas. As enumerações estão em uma API, portanto, usar as soluções propostas até agora não é apenas uma opção.
Respostas:
Você pode conferir o GCCXML .
A execução do GCCXML no seu código de exemplo produz:
Você pode usar qualquer idioma que preferir para extrair as tags Enumeration e EnumValue e gerar o código desejado.
fonte
X-macros são a melhor solução. Exemplo:
colours.def:
No entanto, eu geralmente prefiro o método a seguir, para que seja possível ajustar um pouco a string.
fonte
#define X(a, b) #b
. Isso só é necessário se os olhares definição como esteX(Red, red)
, em vez da definição mostrada na resposta,X(Red, "red")
@hydroo: Sem o arquivo extra:
fonte
MetaSyntacticVariableNames[]
parte, ser de uma declaração de classe, fazendo um métodostatic const char* getNameByEnum(MetaSyntacticVariable e) { /*code to return the static string*/ }
O que costumo fazer é criar uma matriz C com os nomes na mesma ordem e posição dos valores da enumeração.
por exemplo.
então você pode usar a matriz em locais onde deseja um valor legível por humanos, por exemplo
Você pode experimentar um pouco com o operador de stringing (consulte # na referência do pré-processador) que fará o que você deseja, em algumas circunstâncias - por exemplo:
irá imprimir "vermelho" para stdout. Infelizmente, não funcionará para uma variável (pois você imprimirá o nome da variável)
fonte
Eu tenho uma macro incrivelmente simples de usar que faz isso de uma maneira completamente SECA. Envolve macros variadicas e alguma mágica simples de análise. Aqui vai:
Para usar isso em seu código, basta:
fonte
O QT é capaz de extrair isso de (graças ao compilador de objetos meta):
Fonte
fonte
Isso pode ser feito em C ++ 11
fonte
Acabei de reinventar esta roda hoje e pensei em compartilhá-la.
Essa implementação não requer nenhuma alteração no código que define as constantes, que podem ser enumerações ou
#define
s ou qualquer outra coisa que se refira a um número inteiro - no meu caso, eu tinha símbolos definidos em termos de outros símbolos. Também funciona bem com valores esparsos. Ele ainda permite vários nomes para o mesmo valor, retornando sempre o primeiro. A única desvantagem é que você precisa criar uma tabela com as constantes, que podem ficar desatualizadas à medida que novas são adicionadas, por exemplo.Um exemplo de como você o usaria:
A
IdToName
função dependestd::lower_bound
de fazer pesquisas rápidas, o que requer que a tabela seja classificada. Se as duas primeiras entradas da tabela estiverem com defeito, a função a classificará automaticamente.Edit: Um comentário me fez pensar em outra maneira de usar o mesmo princípio. Uma macro simplifica a geração de uma grande
switch
declaração.fonte
switch and case
, pois é simples e fácil de entender.Discussão adicional sobre este método
Diretrizes de diretiva de pré-processador para iniciantes
fonte
Interessante ver o número de maneiras. aqui está um que eu usei há muito tempo:
no arquivo myenummap.h:
em main.cpp
Não é const, mas é conveniente.
Aqui está outra maneira que usa os recursos do C ++ 11. Isso é const, não herda um contêiner STL e é um pouco mais organizado:
fonte
Uso:
fonte
MyEnum x = MyEnum::TWO;
. Publiquei minha edição da sua turma para apoiar isso.Solução macro da Suma é boa. Você não precisa ter duas macros diferentes. Felizmente, o C ++ incluirá um cabeçalho duas vezes. Apenas deixe de fora a guarda de inclusão.
Então você teria um foobar.h definindo apenas
e você incluiria assim:
enumfactory.h fará 2
#include ENUMFACTORY_ARGUMENT
s. No primeiro turno, ele expande o ENUM como o de SumaDECLARE_ENUM
; no segundo turno, ENUM funciona comoDEFINE_ENUM
.Você também pode incluir enumfactory.h várias vezes, desde que passe diferentes # define para ENUMFACTORY_ARGUMENT
fonte
Observe que, idealmente, sua função de conversão retornará um const char *.
Se você puder colocar suas enumerações em seus arquivos de cabeçalho separados, talvez faça algo assim com macros (oh, isso será feio):
Onde enum_def.h possui:
E enum_conv.h tem:
E, finalmente, colour.h tem:
E você pode usar a função de conversão como:
Isso é feio, mas é a única maneira (no nível do pré-processador) que permite definir sua enumeração apenas em um único local no seu código. Portanto, seu código não está sujeito a erros devido a modificações na enumeração. Sua definição de enumeração e a função de conversão estarão sempre sincronizadas. No entanto, repito, isso é feio :)
fonte
Outra resposta: em alguns contextos, faz sentido definir sua enumeração em um formato sem código, como um arquivo CSV, YAML ou XML e, em seguida, gere o código de enumeração C ++ e o código de seqüência de caracteres a partir da definição. Essa abordagem pode ou não ser prática em seu aplicativo, mas é algo a ter em mente.
fonte
Esta é uma modificação na resposta @ user3360260. Possui os seguintes novos recursos
MyEnum fromString(const string&)
Apoio, suporteUso:
Aqui está o código
Observe que a conversão paraString é uma pesquisa rápida, enquanto a conversão deString é uma pesquisa linear lenta. Mas as strings são tão caras de qualquer maneira (e o IO do arquivo associado), que não senti a necessidade de otimizar ou usar um bimap.
fonte
Aqui está uma solução de arquivo único (com base na resposta elegante de @Marcin:
fonte
Eu faço isso com classes de wrapper enum lado a lado separadas, que são geradas com macros. Existem várias vantagens:
A desvantagem, é claro, é que eu preciso duplicar os valores de enum nas classes do formatador e não tenho nenhum script para gerá-los. Fora isso, porém, parece funcionar muito bem.
Aqui está um exemplo de enumeração da minha base de código, sem todo o código da estrutura que implementa as macros e modelos, mas você pode ter uma idéia:
A ideia é, em vez de usar EHelpLocation, você usa SEHelpLocation; tudo funciona da mesma maneira, mas você obtém a verificação de alcance e um método 'Format ()' na própria variável enum. Se você precisar formatar um valor independente, poderá usar CEnumFormatter_EHelpLocation :: FormatEnum (...).
Espero que isso seja útil. Sei que isso também não aborda a pergunta original sobre um script para realmente gerar a outra classe, mas espero que a estrutura ajude alguém a tentar resolver o mesmo problema ou escreva esse script.
fonte
É um software não lançado, mas parece que o BOOST_ENUM de Frank Laub poderia ser o ideal. A parte de que gosto é que você pode definir uma enumeração no escopo de uma classe que a maioria das enumerações baseadas em macro geralmente não permite. Está localizado no Boost Vault em: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=enum_rev4.6.zip&directory=& Não há nenhum desenvolvimento desde 2006, então não vejo saber quão bem ele compila com os novos lançamentos do Boost. Procure em libs / test um exemplo de uso.
fonte
Esta foi a minha solução com o BOOST:
Para criar enum, declare:
Para conversões:
fonte
Quero postar isso caso alguém considere útil.
No meu caso, eu simplesmente preciso gerar
ToString()
eFromString()
funções para uma única enumeração C ++ 11 a partir de um único.hpp
arquivo.Eu escrevi um script python que analisa o arquivo de cabeçalho que contém os itens enum e gera as funções em um novo
.cpp
arquivo.Você pode adicionar esse script no CMakeLists.txt com execute_process ou como um evento de pré-compilação no Visual Studio. O
.cpp
arquivo será gerado automaticamente, sem a necessidade de atualizá-lo manualmente sempre que um novo item de enumeração for adicionado.generate_enum_strings.py
Exemplo:
ErrorCode.hpp
Corre
python generate_enum_strings.py ErrorCode.hpp
Resultado:
ErrorCode.cpp
fonte
Adicionando ainda mais simplicidade de uso à fantástica resposta de Jasper Bekkers :
Configure uma vez:
Então, para uso:
fonte
Você poderia usar uma biblioteca de reflexão, como Ponder . Você registra as enumerações e pode convertê-las com a API.
fonte
Um problema com a resposta 0 é que os valores binários da enumeração não iniciam necessariamente em 0 e não são necessariamente contíguos.
Quando eu preciso disso, eu normalmente:
fonte
O script ruby a seguir tenta analisar os cabeçalhos e construir as fontes necessárias juntamente com os cabeçalhos originais.
O uso de expressões regulares torna esse "analisador" bastante frágil; talvez não seja possível manipular seus cabeçalhos específicos normalmente.
Digamos que você tenha um cabeçalho toto / ah, contendo definições para enumerações MyEnum e MyEnum2. O script criará:
Soluções mais robustas seriam:
fonte
Essa é basicamente a única maneira de fazer isso (uma matriz de strings também pode funcionar).
O problema é que, quando um programa C é compilado, o valor binário da enumeração é tudo o que é usado e o nome desaparece.
fonte
Aqui está um programa CLI que escrevi para converter facilmente enumerações em strings. É fácil de usar e leva cerca de 5 segundos para fazer isso (incluindo o tempo de acessar o diretório que contém o programa e executá-lo, passando para ele o arquivo que contém a enumeração).
Faça o download aqui: http://www.mediafire.com/?nttignoozzz
Tópico de discussão aqui: http://cboard.cprogramming.com/projects-job-recruitment/127488-free-program-im-sharing-convertenumtostrings.html
Execute o programa com o argumento "--help" para obter uma descrição de como usá-lo.
fonte
Há pouco tempo, fiz um truque para exibir enumerações corretamente no QComboBox e definir definições de enumerações e representações de string como uma declaração
Agora você
enumeration::enum_singleton<your_enum>::instance()
pode converter enums em strings. Se você substituirkv_storage_t
porboost::bimap
, também poderá fazer a conversão para trás. A classe base comum para o conversor foi introduzida para armazená-lo no objeto Qt, porque os objetos Qt não podiam ser modelosAparência anterior
fonte
Como variante, use lib simples> http://codeproject.com/Articles/42035/Enum-to-String-and-Vice-Versa-in-C
No código
adicionar linhas
Funciona bem, se os valores em enum não forem publicados .
Exemplo de uso
e vice versa
fonte
Aqui está uma tentativa de obter operadores de fluxo << e >> no enum automaticamente com apenas um comando macro de uma linha ...
Definições:
Uso:
Não tenho certeza sobre as limitações desse esquema ... comentários são bem-vindos!
fonte
fonte