Comment les énumérations C bitflag doivent-elles être traduites en C ++?
Question
C ++ est principalement un sur-ensemble de C, mais pas toujours. En particulier, alors que les valeurs d’énumération converties implicitement en C et C ++ sont converties en int, l’inverse n’est pas vrai: c’est seulement en C que les ints sont reconvertis en valeurs d’énumération. Ainsi, les drapeaux définis par les déclarations d’énumération ne fonctionnent pas correctement. Par conséquent, c’est OK en C mais pas en C ++:
typedef enum Foo
{
Foo_First = 1<<0,
Foo_Second = 1<<1,
} Foo;
int main(void)
{
Foo x = Foo_First | Foo_Second; // error in C++
return 0;
}
Comment ce problème devrait-il être traité efficacement et correctement, idéalement sans nuire à la nature conviviale du débogueur consistant à utiliser Foo comme type de variable (il se décompose en composant, le bitflags dans les montres, etc.)?
Considérez également qu’il peut y avoir des centaines d’énumérations de drapeaux de ce type et plusieurs milliers de points d’utilisation. Idéalement, une surcharge efficace de la part d’un opérateur suffirait, mais elle devrait être efficace; l'application à laquelle je pense est liée au calcul et a la réputation d'être rapide.
Clarification: je traduis un grand programme C (& 30000) C en C ++, je recherche donc une traduction efficace, à la fois au moment de l’exécution et au moment du développement. Il suffit parfois de plusieurs semaines pour insérer des modèles dans tous les emplacements appropriés.
La solution
Pourquoi ne pas simplement renvoyer le résultat à un Foo?
Foo x = Foo(Foo_First | Foo_Second);
EDIT: Je n’ai pas compris l’ampleur de votre problème lorsque j’ai répondu à cette question pour la première fois. Ce qui précède fonctionnera pour faire quelques corrections ponctuelles. Pour ce que vous voulez faire, vous devrez définir un | opérateur qui prend 2 arguments Foo et retourne un Foo:
Foo operator|(Foo a, Foo b)
{
return Foo(int(a) | int(b));
}
Les internautes sont là pour empêcher une récursion indésirable.
Autres conseils
Cela ressemble à une application idéale pour un casting - vous devez dire au compilateur que vous voulez effectivement instancier un Foo avec un entier aléatoire.
Bien sûr, techniquement parlant, Foo_First | Foo_Second n'est pas une valeur valide pour un Foo.
Laissez le résultat sous la forme d'un entier ou statique:
Foo x = static_cast<Foo>(Foo_First | Foo_Second); // not an error in C++