Um enum X : int
(C #) ou enum class X : int
(C ++ 11) é um tipo que possui um campo interno oculto int
que pode conter qualquer valor. Além disso, várias constantes predefinidas de X
são definidas na enumeração. É possível converter a enumeração em seu valor inteiro e vice-versa. Isso tudo é verdade em C # e C ++ 11.
Em C #, as enums não são usadas apenas para armazenar valores individuais, mas também para combinar combinações de bit a bit de sinalizadores, conforme recomendação da Microsoft . Tais enumerações são (geralmente, mas não necessariamente) decoradas com o [Flags]
atributo Para facilitar a vida dos desenvolvedores, os operadores bit a bit (OR, AND, etc ...) estão sobrecarregados para que você possa fazer algo assim (C #):
void M(NumericType flags);
M(NumericType.Sign | NumericType.ZeroPadding);
Eu sou um desenvolvedor experiente de C #, mas tenho programado C ++ apenas há alguns dias e não sou conhecido pelas convenções de C ++. Pretendo usar uma enumeração C ++ 11 da mesma maneira que costumava fazer em C #. No C ++ 11, os operadores bit a bit em enumerações com escopo não são sobrecarregados, então eu queria sobrecarregá-los .
Isso solicitou um debate, e as opiniões parecem variar entre três opções:
Uma variável do tipo enum é usada para conter o campo de bits, semelhante ao C #:
void M(NumericType flags); // With operator overloading: M(NumericType::Sign | NumericType::ZeroPadding); // Without operator overloading: M(static_cast<NumericType>(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding)));
Mas isso contraria a filosofia de enumeração fortemente tipada das enumerações com escopo definido em C ++ 11.
Use um número inteiro simples se desejar armazenar uma combinação de enumerações bit a bit:
void M(int flags); M(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding));
Mas isso reduziria tudo a um
int
, deixando você sem idéia de qual tipo você deveria colocar no método.Escreva uma classe separada que sobrecarregará os operadores e mantenha os sinalizadores bit a bit em um campo inteiro oculto:
class NumericTypeFlags { unsigned flags_; public: NumericTypeFlags () : flags_(0) {} NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {} //...define BITWISE test/set operations }; void M(NumericTypeFlags flags); M(NumericType::Sign | NumericType::ZeroPadding);
( código completo do usuário315052 )
Mas você não possui o IntelliSense ou qualquer outro suporte para sugerir os valores possíveis.
Sei que essa é uma pergunta subjetiva , mas: que abordagem devo usar? Qual abordagem, se houver, é a mais amplamente reconhecida em C ++? Qual abordagem você usa ao lidar com campos de bits e por quê ?
É claro que, como todas as três abordagens funcionam, estou procurando razões factuais e técnicas, convenções geralmente aceitas e não apenas preferências pessoais.
Por exemplo, devido ao meu background em C #, eu costumo seguir a abordagem 1 em C ++. Isso tem o benefício adicional de que meu ambiente de desenvolvimento pode me sugerir os valores possíveis e, com operadores sobrecarregados de enum, isso é fácil de escrever e entender, e bastante limpo. E a assinatura do método mostra claramente que tipo de valor espera. Mas a maioria das pessoas aqui discorda de mim, provavelmente por um bom motivo.
enum E { A = 1, B = 2, C = 4, };
, o intervalo é 0..7
(3 bits). Portanto, o padrão C ++ garante explicitamente que o número 1 sempre será uma opção viável. [Especificamente, o enum class
padrão é aquele a enum class : int
menos que seja especificado de outra forma e, portanto, sempre tem um tipo subjacente fixo.])