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!

questionAnswers(4)

yourAnswerToTheQuestion