Conte com o enum C ++ automatic
Cheguei a um padrão ao escrever enums em C ++. É assim:
class Player
{
public:
class State
{
public:
typedef enum
{
Stopped,
Playing,
Paused
}PossibleValues;
static const int Count() {return Paused+1;};
static const PossibleValues Default() {return Stopped;};
};
//...
}
Isso resolve alguns dos problemas comuns com enums, como poluição de namespaces externos, etc. Mas ainda há uma coisa de que não gosto: O Count () é feito manualmente. Existem apenas duas maneiras que eu sei como fazer: esta é calculada a partir de Last + 1; ou escreva simples codificado.
A pergunta é: Existe alguma maneira, como usar macros de pré-processamento, que recebe automaticamente a contagem, para colocá-lo depois no método Count ()? Atenção: Eu não quero ter um último elemento falso chamado Count dentro do enum, poluindo-o!
Desde já, obrigado!
ATUALIZAÇÃO 1:
Há uma discussão interessante sobreImplementação da reflexão enum N4428 no padrão C ++ 11 (parcial) para uma proposta de enums mais avançados.
ATUALIZAÇÃO 2:
Documento interessanteN4451- Reflexão estática (rev. 3) em suas seções 3.16, 3.17, A.7, A.8 sobre MetaEnums e MetaEnumClasses.
ATUALIZAÇÃO 3:
Eu vim para outro padrão interessante usando uma classe enum, depois que eu vihttps://bytes.com/topic/c/answers/127908-numeric_limits-specialization#post444962. Se a classe enumlista de enumeradores é continuamente inteiro, definindo seu máximo e seu mínimo, podemos verificar se um valor pertence a ele ou não.
Se o propósito de usar oCount()
método noPlayer::State
foi verificar se um valor estava no enum, esse propósito também foi alcançado com a abordagem numeric_limits, e é até mesmo superior, já que não é necessário que a lista de enumeradores comece com um item de valor ZERO!
enum class Drink
{
Water,
Beer,
Wine,
Juice,
};
#pragma push_macro("min")
#undef min
#pragma push_macro("max")
#undef max
namespace std
{
template <> class numeric_limits < Drink >
{
public:
static const/*expr*/ bool is_specialized = true;
static const/*expr*/ Drink min() /*noexcept*/ { return Drink::Water; }
static const/*expr*/ Drink max() /*noexcept*/ { return Drink::Juice; }
static const/*expr*/ Drink lowest() /*noexcept*/ { return Drink::Water; }
static const/*expr*/ Drink default() /*noexcept*/ { return Drink::Beer; }
};
}
#pragma pop_macro("min")
#pragma pop_macro("max")
CASOS DE USO:
Uma variável do aplicativo:
Drink m_drink;
que no construtor é inicializado com:
m_drink = numeric_limits<Drink>::default();
Na inicialização de um formulário, posso fazer:
pComboDrink->SetCurSel(static_cast<int>(theApp.m_drink));
Nele, para adaptar a interface às alterações feitas pelo usuário, posso fazer um switch com valores de classe de enumeração com escopo definido:
switch (static_cast<Drink>(pComboDrink->GetCurSel()))
{
case Drink::Water:
case Drink::Juice:
pAlcohoolDegreesControl->Hide();
break;
case Drink::Beer:
case Drink::Wine:
pAlcohoolDegreesControl->Show();
break;
default:
break;
}
E no procedimento de confirmação do diálogo (OnOK
), Posso verificar se o valor está fora dos limites, antes de salvá-lo no respectivo aplicativo var:
int ix= pComboDrink->GetCurSel();
if (ix == -1)
return FALSE;
#pragma push_macro("min")
#undef min
#pragma push_macro("max")
#undef max
if (ix < static_cast<int> (std::numeric_limits<Drink>::min()) || ix > static_cast<int> (std::numeric_limits<Drink>::max()) )
return FALSE;
#pragma pop_macro("min")
#pragma pop_macro("max")
theApp.m_drink= static_cast<Drink>(ix);
NOTAS:
As palavras-chaveconstexpr
(Eu comentei/*expr*/
, deixando comoconst
) enoexcept
são comentados somente porque o compilador que estou usando (Visual C ++ 2013) não oferece suporte a eles ainda na versão atual.Talvez você não precise da lógica para indefinir temporariamente as macros mín e máx.Eu sei que odefault()
não cabe em um escopo de "limites numéricos"; mas parecia um lugar prático para colocá-lo; até coincide com odefault
palavra que em alguns contextos é uma palavra-chave!