Como posso gerar o valor de um enum class
em C ++ 11? Em C ++ 03 é assim:
#include <iostream>
using namespace std;
enum A {
a = 1,
b = 69,
c= 666
};
int main () {
A a = A::c;
cout << a << endl;
}
em c ++ 0x este código não compila
#include <iostream>
using namespace std;
enum class A {
a = 1,
b = 69,
c= 666
};
int main () {
A a = A::c;
cout << a << endl;
}
prog.cpp:13:11: error: cannot bind 'std::ostream' lvalue to 'std::basic_ostream<char>&&'
/usr/lib/gcc/i686-pc-linux-gnu/4.5.1/../../../../include/c++/4.5.1/ostream:579:5: error: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char, _Traits = std::char_traits<char>, _Tp = A]'
compilado em Ideone.com
Respostas:
Ao contrário de uma enumeração sem escopo, uma enumeração com escopo não é implicitamente conversível em seu valor inteiro. Você precisa explicitamente convertê-lo em um inteiro usando um elenco:
Você pode querer encapsular a lógica em um modelo de função:
usado como:
fonte
as_integer
de uma das minhas bibliotecas de código aberto, CxxReflect (consulte enumeration.hpp ). A biblioteca usa tipos de retorno à direita de forma consistente, em todos os lugares. Para consistência.as_integer
pode ser definido para serconstexpr
usado em contextos onde a expressão constante é necessária.fonte
g++ -std=c++0x enum.cpp
mas estou recebendo um monte de erros do compilador -> pastebin.com/JAtLXan9 . Eu também não consegui obter o exemplo de @james-mcnellis para compilar.É possível fazer com que seu segundo exemplo (ou seja, aquele que usa um enum com escopo definido) funcione usando a mesma sintaxe dos enums sem escopo. Além disso, a solução é genérica e funcionará para todos os enums com escopo definido, em vez de escrever código para cada enum com escopo definido (conforme mostrado na resposta fornecida por @ForEveR ).
A solução é escrever uma
operator<<
função genérica que funcionará para qualquer enum com escopo definido. A solução emprega SFINAE viastd::enable_if
e é a seguinte.fonte
typename
antesstd::underlying_type<T>::type
.error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
. isso parece ser porque quando o fluxo é temporário, o ADL falha e o modelo acima não é uma possibilidade. alguma dica?cout
instruções em uma únicacout
instrução encadeando os<<
operadores. Veja aqui(Não tenho permissão para comentar ainda.) Eu sugeriria as seguintes melhorias para a já excelente resposta de James McNellis:
com
constexpr
: permitindo-me usar um valor de membro enum como tamanho de array em tempo de compilaçãostatic_assert
+is_enum
: para 'garantir' o tempo de compilação que a função executa sth. com enumerações apenas, como sugeridoA propósito, estou me perguntando: por que devo usar
enum class
quando gostaria de atribuir valores numéricos aos membros de minha enumeração ?! Considerando o esforço de conversão.Talvez eu voltasse ao normal,
enum
como sugeri aqui: Como usar enums como sinalizadores em C ++?Mais um sabor (melhor) sem static_assert, baseado na sugestão de @TobySpeight:
fonte
T
para o qualstd::underlying_type<T>::type
existe, masstd::is_enum<T>::value
é falso? Se não, então ostatic_assert
adiciona nenhum valor.Enumeration
não for um tipo de enum completo. Nesse caso, pode já ser tarde demais, pois é usado no tipo de retorno. Talvez pudéssemos especificarstd::enable_if<std::is_enum<Enumeration>::value, std::underlying_type<Enumeration>::type>
como o tipo de retorno? Claro, é muito mais fácil (e as mensagens de erro muito mais claras) se você tiver um compilador com suporte para Conceitos ...Para escrever mais simples,
fonte
A seguir funcionou para mim em C ++ 11:
fonte
Você poderia fazer algo assim:
fonte