Freqüentemente, são necessários vários tipos enumerados juntos. Às vezes, há um conflito de nomes. Duas soluções vêm à mente: use um namespace ou nomes de elemento enum 'maiores'. Ainda assim, a solução de namespace tem duas implementações possíveis: uma classe fictícia com enum aninhado ou um namespace completo.
Estou procurando os prós e os contras das três abordagens.
Exemplo:
// oft seen hand-crafted name clash solution
enum eColors { cRed, cColorBlue, cGreen, cYellow, cColorsEnd };
enum eFeelings { cAngry, cFeelingBlue, cHappy, cFeelingsEnd };
void setPenColor( const eColors c ) {
switch (c) {
default: assert(false);
break; case cRed: //...
break; case cColorBlue: //...
//...
}
}
// (ab)using a class as a namespace
class Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
class Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
switch (c) {
default: assert(false);
break; case Colors::cRed: //...
break; case Colors::cBlue: //...
//...
}
}
// a real namespace?
namespace Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
namespace Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
switch (c) {
default: assert(false);
break; case Colors::cRed: //...
break; case Colors::cBlue: //...
//...
}
}
enum e {...}
, enums podem ser anônimos, ou sejaenum {...}
, o que faz muito mais sentido quando agrupado em namespace ou classe.Respostas:
Resposta original C ++ 03:
A vantagem de a
namespace
(sobre aclass
) é que você pode usarusing
declarações quando quiser.O problema de usar um
namespace
é que os namespaces podem ser expandidos em outras partes do código. Em um grande projeto, você não teria a garantia de que duas enums distintas não pensam que são chamadaseFeelings
Para um código de aparência mais simples, eu uso um
struct
, já que você provavelmente deseja que o conteúdo seja público.Se você está fazendo qualquer uma dessas práticas, está à frente da curva e provavelmente não precisa examinar isso mais profundamente.
Conselho mais recente, C ++ 11:
Se você estiver usando C ++ 11 ou posterior,
enum class
o escopo dos valores enum será implicitamente dentro do nome do enum.Com
enum class
você perderá conversões implícitas e comparações com tipos inteiros, mas na prática isso pode ajudá-lo a descobrir códigos ambíguos ou com erros.fonte
Para sua informação, em C ++ 0x há uma nova sintaxe para casos como o que você mencionou (consulte a página wiki de C ++ 0x )
fonte
Eu hibridizei as respostas anteriores para algo assim: (EDITAR: Isso só é útil para pré-C ++ 11. Se você estiver usando C ++ 11, use
enum class
)Eu tenho um grande arquivo de cabeçalho que contém todos os meus enums do projeto, porque esses enums são compartilhados entre as classes de trabalho e não faz sentido colocar os enums nas próprias classes de trabalho.
O
struct
evita o açúcar sintático public: e otypedef
permite que você realmente declare variáveis dessas enums dentro de outras classes de trabalho.Não acho que usar um namespace ajude em nada. Talvez seja porque sou um programador C #, e você precisa usar o nome do tipo enum ao referir-se aos valores, então estou acostumado a isso.
...
fonte
Eu definitivamente evitaria usar uma classe para isso; use um namespace em vez disso. A questão se resume a usar um namespace ou ids exclusivos para os valores de enum. Pessoalmente, eu usaria um namespace para que meus ids fossem mais curtos e, com sorte, mais autoexplicativos. Então, o código do aplicativo poderia usar uma diretiva 'using namespace' e tornar tudo mais legível.
Do seu exemplo acima:
fonte
Colors someColor = Red;
, porque o namespace não constitui um tipo. Você teria que escrever emColors::e someColor = Red;
vez disso, o que é bastante contra-intuitivo.Colors::e someColor
mesmo com umstruct/class
se quisesse usá-lo em umaswitch
declaração? Se você usar um anônimoenum
, o switch não será capaz de avaliar astruct
.const e c
parece dificilmente legível para mim :-) Não faça isso. Usar um namespace, entretanto, está bem.Uma diferença entre usar uma classe ou um namespace é que a classe não pode ser reaberta como um namespace pode. Isso evita a possibilidade de que o namespace possa ser abusado no futuro, mas também existe o problema de que você também não pode adicionar ao conjunto de enumerações.
Um possível benefício de usar uma classe é que eles podem ser usados como argumentos de tipo de modelo, o que não é o caso para namespaces:
Pessoalmente, não sou um fã de usar e prefiro os nomes totalmente qualificados, então não vejo isso como uma vantagem para os namespaces. No entanto, esta provavelmente não é a decisão mais importante que você fará em seu projeto!
fonte
A vantagem de usar uma classe é que você pode construir uma classe completa em cima dela.
Como mostra o exemplo acima, usando uma classe, você pode:
Apenas observe que você precisa declarar
operator enum_type()
para que C ++ saiba como converter sua classe em enum subjacente. Caso contrário, você não poderá passar o tipo para umaswitch
instrução.fonte
Como os enums têm como escopo seu escopo delimitador, provavelmente é melhor envolvê-los em algo para evitar poluir o namespace global e ajudar a evitar colisões de nomes. Eu prefiro um namespace à classe simplesmente porque
namespace
parece um saco de contenção, enquantoclass
parece um objeto robusto (cf. o debatestruct
vs.class
). Um possível benefício de um namespace é que ele pode ser estendido posteriormente - útil se você estiver lidando com código de terceiros que não pode ser modificado.Isso tudo é discutível, é claro, quando obtemos classes enum com C ++ 0x.
fonte
Eu também tendo a encerrar minhas enums nas aulas.
Conforme assinalado por Richard Corden, o benefício de uma classe é que ela é um tipo no sentido de c ++ e, portanto, você pode usá-la com modelos.
Eu tenho a classe toolbox :: Enum especial para minhas necessidades, que me especializo para todos os modelos que fornecem funções básicas (principalmente: mapear um valor de enum para um std :: string para que as E / S sejam mais fáceis de ler).
Meu pequeno modelo também tem o benefício adicional de realmente verificar os valores permitidos. O compilador é meio negligente em verificar se o valor realmente está no enum:
Sempre me incomodou que o compilador não pegasse isso, já que você ficou com um valor enum que não tem sentido (e que você não esperaria).
Similarmente:
Mais uma vez, main retornará um erro.
O problema é que o compilador irá ajustar o enum na menor representação disponível (aqui precisamos de 2 bits) e que tudo que se encaixar nesta representação é considerado um valor válido.
Há também o problema de que às vezes você prefere ter um loop nos valores possíveis em vez de um switch, para não ter que modificar todos os switches cada vez que adiciona um valor ao enum.
Em suma, meu pequeno ajudante realmente facilita as coisas para meus enums (é claro, ele adiciona alguma sobrecarga) e só é possível porque aninho cada enum em sua própria estrutura :)
fonte