Ces réponses ne semblent pas couvrir le problème qui intn'est peut-être pas assez important! ( [C++03: 7.2/5])
Courses de légèreté en orbite le
Fait intéressant, vous pouvez définir des operator++énumérations; cependant, vous pouvez donc le faire for(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++). Notez que vous devez effectuer un cast 0vers Enum_Ecar C ++ interdit les opérateurs d'affectation sur les énumérations.
weberc2
S'il y avait un opérateur de compilation, similaire à la façon dont sizeof fonctionne, qui pouvait émettre un littéral std :: initializer_list comprenant les valeurs de l'énumération, nous aurions une solution et n'impliquerions aucun temps d'exécution.
Veuillez noter que l'énumération Lastest destinée à être ignorée par l'itération. En utilisant cette "fausse" Lasténumération, vous n'avez pas à mettre à jour votre condition de terminaison dans la boucle for à la dernière "vraie" énumération chaque fois que vous souhaitez ajouter une nouvelle énumération. Si vous souhaitez ajouter d'autres énumérations plus tard, ajoutez-les simplement avant Last. La boucle dans cet exemple fonctionnera toujours.
Bien sûr, cela tombe en panne si les valeurs d'énumération sont spécifiées:
enumFoo{One=1,Two=9,Three=4,Last};
Cela illustre le fait qu'une énumération n'est pas vraiment destinée à parcourir. La manière typique de traiter une énumération consiste à l'utiliser dans une instruction switch.
Si vous voulez vraiment énumérer, remplissez les valeurs d'énumération dans un vecteur et parcourez-le. Cela traitera également correctement les valeurs d'énumération spécifiées.
Notez que, dans la première partie de l'exemple, si vous souhaitez utiliser 'i' comme une énumération Foo et non un int, vous devrez le convertir statiquement comme: static_cast <Foo> (i)
Clayton
5
Vous sautez également Last in the loop. Doit être <= dernier
Tony
20
@Tony Last est censé être ignoré. Si vous souhaitez ajouter d'autres énumérations plus tard, ajoutez-les avant Last ... la boucle du premier exemple fonctionnera toujours. En utilisant une "fausse" dernière énumération, vous n'avez pas à mettre à jour votre condition de terminaison dans la boucle for vers la dernière "vraie" énumération chaque fois que vous souhaitez ajouter une nouvelle énumération.
timidpueo
Sauf que maintenant vous avez réellement alloué de la mémoire quand une énumération, à condition qu'elle soit indexée zéro et strictement continue, peut faire cette tâche sans allouer de mémoire.
Cloud
1
Notez que pour que cette définition d'énumération soit sûre pour les mises à jour, il faut définir une valeur UNKNOWN = 0. De plus, je suggérerais simplement de supprimer le defaultcas lors du basculement des valeurs d'énumération car cela pourrait masquer les cas où la gestion des valeurs a été oubliée jusqu'à l'exécution. Au lieu de cela, vous devez coder en dur toutes les valeurs et utiliser le UNKNOWNchamp pour détecter les incompatibilités.
Benjamin Bannier
53
#include<iostream>#include<algorithm>namespaceMyEnum{enumType{
a =100,
b =220,
c =-1};staticconstTypeAll[]={ a, b, c };}void fun(constMyEnum::Type e ){
std::cout << e << std::endl;}int main(){// allfor(constauto e :MyEnum::All)
fun( e );// somefor(constauto e :{MyEnum::a,MyEnum::b })
fun( e );// all
std::for_each( std::begin(MyEnum::All), std::end(MyEnum::All), fun );return0;}
Merci! Notez que si vous traversez des fichiers / classes et si la compatibilité MS vous pose des problèmes avec les constantes non entières déclarées par l'en-tête, cela aide sous mon compilateur à mettre explicitement la taille dans le type dans l'en-tête: static const Type All[3];et alors je suis capable pour initialiser dans la source: const MyEnum::Type MyEnum::All[3] = { a, b, c }; Avant de faire cela, je recevais des Error in range-based for...erreurs odieuses (parce que le tableau avait une taille inconnue). Compris cela grâce à une réponse connexe
sage
1
La version tableau est très conviviale de copier-coller. La réponse la plus satisfaisante est d'ailleurs "NON" ou "uniquement pour séquentiel". Probablement même compatible avec les macros.
Paulo Neves
1
cela peut être une bonne solution pour les énumérations avec un petit nombre d'éléments, mais pour les énumérations avec un grand nombre d'éléments, il ne doit pas bien s'adapter.
kato2
20
Si votre énumération commence par 0 et l'incrément est toujours 1.
Avec c ++ 11, il existe en fait une alternative: écrire un simple itérateur personnalisé basé sur des modèles.
supposons que votre énumération soit
enumclass foo {
one,
two,
three
};
Ce code générique fera l'affaire, assez efficacement - placé dans un en-tête générique, il vous servira pour toute énumération que vous pourriez avoir besoin de parcourir:
#include<type_traits>template<typename C, C beginVal, C endVal>classIterator{typedeftypename std::underlying_type<C>::type val_t;int val;public:Iterator(const C & f): val(static_cast<val_t>(f)){}Iterator(): val(static_cast<val_t>(beginVal)){}Iteratoroperator++(){++val;return*this;}
C operator*(){returnstatic_cast<C>(val);}Iterator begin(){return*this;}//default ctor is goodIterator end(){staticconstIterator endIter=++Iterator(endVal);// cache itreturn endIter;}booloperator!=(constIterator& i){return val != i.val;}};
for(foo i : fooIterator()){//notice the parentheses!
do_stuff(i);}
L'hypothèse selon laquelle vous n'avez pas de lacunes dans votre énumération est toujours vraie; il n'y a aucune hypothèse sur le nombre de bits réellement nécessaires pour stocker la valeur d'énumération (grâce à std :: sous-jacent_type)
Je ne sais pas pourquoi cela a été rejeté. C'est une solution raisonnable.
Paul Brannan
11
Je pense que c'est parce que les entrées doivent être conservées à deux endroits.
Ant
C ++ permet-il la for (NodePosition pos : NodePositionVector)syntaxe? Pour autant que je sache, il s'agit de la syntaxe Java, et vous aurez besoin d'itérateurs en C ++ pour faire quelque chose d'équivalent.
thegreatjedi
3
@thegreatjedi Depuis C ++ 11, vous pouvez, encore plus simplement: for (auto pos: NodePositionVector) {..}
Enzojz
@thegreatjedi Il aurait été plus rapide de rechercher, voire de compiler un programme de test, que de poser cette question. Mais oui, depuis C ++ 11, c'est une syntaxe C ++ parfaitement valide, que le compilateur traduit en code équivalent (et beaucoup plus verbeux / moins abstrait), généralement via des itérateurs; voir cppreference . Et, comme l'a dit Enzojz, C ++ 11 a également ajouté auto, vous n'avez donc pas à déclarer explicitement le type des éléments, sauf si vous (A) devez utiliser un opérateur de conversion ou (B) n'aimez pas autopour une raison quelconque . La plupart des forutilisateurs de la autogamme utilisent AFAICT
underscore_d
9
Je le fais souvent comme ça
enumEMyEnum{
E_First,
E_Orange = E_First,
E_Green,
E_White,
E_Blue,
E_Last
}for(EMyEnum i = E_First; i < E_Last; i =EMyEnum(i +1)){}
ou sinon successif, mais avec pas régulier (par exemple drapeaux de bits)
mais, à quoi sert d'imprimer les valeurs bit par bit?
Anu
1
Pour utiliser des énumérations pour créer des masques de bits. Par exemple, combinez plusieurs options dans une seule variable, puis utilisez le FOR pour tester chaque option. Correction de mon message avec un meilleur exemple.
Niki
Je n'arrive toujours pas à l'utiliser (et votre message montre toujours l'ancien exemple)! Utiliser enum comme bitmasks est vraiment utile, mais n'a pas pu connecter les points! pourriez-vous s'il vous plaît élaborer un peu dans votre exemple en détail, vous pouvez également mettre le code supplémentaire.
Anu
@anu Désolé, vous n'avez pas vu votre commentaire. Ajout de la classe Frog comme exemple de masque de bits
Niki
8
Vous ne pouvez pas avec une énumération. Peut-être qu'un enum n'est pas le mieux adapté à votre situation.
Une convention courante consiste à nommer la dernière valeur d'énumération quelque chose comme MAX et à l'utiliser pour contrôler une boucle à l'aide d'un int.
Il existe plusieurs exemples ici qui démontrent le contraire. Dans votre propre déclaration, vous vous contredisez (deuxième ligne).
Niki
6
Quelque chose qui n'a pas été couvert dans les autres réponses = si vous utilisez des énumérations C ++ 11 fortement typées, vous ne pouvez pas les utiliser ++ni les utiliser + int. Dans ce cas, une solution un peu plus compliquée est requise:
enumCount{ zero, one, two, three };
for_range (Count, c, zero, three){
cout <<"forward: "<< c << endl;}
Il peut être utilisé pour parcourir en avant et en arrière à travers des entiers, des énumérations et des caractères non signés:
for_range (unsigned, i,10,0){
cout <<"backwards i: "<< i << endl;}
for_range (char, c,'z','a'){
cout << c << endl;}
Malgré sa définition maladroite, il est très bien optimisé. J'ai regardé le désassembleur dans VC ++. Le code est extrêmement efficace. Ne vous découragez pas mais les trois pour les instructions: le compilateur ne produira qu'une seule boucle après optimisation! Vous pouvez même définir des boucles fermées:
unsigned p[4][5];
for_range (Count, i, zero,three)
for_range(unsignedint, j,4,0){
p[i][j]=static_cast<unsigned>(i)+j;}
Vous ne pouvez évidemment pas parcourir les types énumérés avec des lacunes.
Vous ne pouvez surcharger aucun opérateur sur les types énumérés C ou C ++. À moins que vous ne deviez créer une structure / classe qui émule une énumération de valeurs.
Surcharger l'incrément / décrément nécessite de prendre une décision sur ce qu'il faut faire en cas de débordement
Éponyme
3
En supposant que l'énumération est numérotée séquentiellement, les erreurs sont sujettes. En outre, vous souhaiterez peut-être parcourir les énumérateurs sélectionnés uniquement. Si ce sous-ensemble est petit, le boucler explicitement pourrait être un choix élégant:
enumItem{Man,Wolf,Goat,Cabbage};// or enum classfor(auto item :{Wolf,Goat,Cabbage}){// or Item::Wolf, ...// ...}
C'est une belle option, je pense. Doit faire partie d'une spécification C ++ plus récente que celle que j'utilisais lorsque j'ai posé la question que je devine?
Adam
Oui. Il itère sur une liste std :: initializer_list <Item>. lien .
marski
2
Si vous n'aimez pas polluer votre énumération avec un élément COUNT final (car peut-être que si vous utilisez également l'énumération dans un commutateur, le compilateur vous avertira d'un cas manquant COUNT :), vous pouvez le faire:
enumColour{Red,Green,Blue};constColourLastColour=Blue;Colour co(0);while(true){// do stuff with co// ...if(co ==LastColour)break;
co =Colour(co+1);}
Voici une autre solution qui ne fonctionne que pour les énumérations contiguës. Il donne l'itération attendue, à l'exception de la laideur dans l'incrément, qui est à sa place, car c'est ce qui est cassé en C ++.
enumBar{One=1,Two,Three,End_Bar// Marker for end of enum; };for(Bar foo =One; foo <End_Bar; foo =Bar(foo +1)){// ...}
L'incrémentation peut être raccourcie foo = Bar(foo + 1).
HolyBlackCat
Merci, HolyBlackCat, j'ai incorporé votre excellente suggestion! Je remarque également que Riot a à peu près cette même solution, mais conforme à un typage fort (et donc plus verbeux).
Ethan Bradford
2
enumclass A {
a0=0, a3=3, a4=4};constexpr std::array<A,3> ALL_A {A::a0, A::a3, A::a4};// constexpr is important herefor(A a: ALL_A){if(a==A::a0 || a==A::a4) std::cout <<static_cast<int>(a);}
UNE constexpr std::array peut itérer même des énumérations non séquentielles sans que le tableau soit instancié par le compilateur. Cela dépend de choses comme l'heuristique d'optimisation du compilateur et si vous prenez l'adresse du tableau.
Dans mes expériences, j'ai trouvé que g++9.1 avec -O3optimisera le tableau ci-dessus s'il y a 2 valeurs non séquentielles ou pas mal de valeurs séquentielles (j'ai testé jusqu'à 6). Mais il ne fait cela que si vous avez une ifdéclaration. (J'ai essayé une instruction qui comparait une valeur entière supérieure à tous les éléments d'un tableau séquentiel et elle a aligné l'itération bien qu'aucun ne soit exclu, mais quand j'ai omis l'instruction if, les valeurs ont été mises en mémoire.) Elle a également inséré 5 valeurs d'une énumération non séquentielle dans [un cas | https://godbolt.org/z/XuGtoc] . Je soupçonne que ce comportement étrange est dû à une heuristique profonde liée aux caches et à la prédiction de branche.
J'aime la sémantique simple de boucle de type plage et je pense qu'elle évoluera encore plus, c'est pourquoi j'aime cette solution.
rtischer8277
2
Dans le livre du langage de programmation C ++ de Bjarne Stroustrup, vous pouvez lire qu'il propose de surcharger le operator++pour votre spécifique enum. enumsont des types définis par l'utilisateur et un opérateur de surcharge existe dans le langage pour ces situations spécifiques.
Vous pourrez coder les éléments suivants:
#include<iostream>enumclassColors{red, green, blue};Colors&operator++(Colors&c,int){switch(c){caseColors::red:return c=Colors::green;caseColors::green:return c=Colors::blue;caseColors::blue:return c=Colors::red;// managing overflowdefault:throw std::exception();// or do anything else to manage the error...}}int main(){Colors c =Colors::red;// casting in int just for convenience of output.
std::cout <<(int)c++<< std::endl;
std::cout <<(int)c++<< std::endl;
std::cout <<(int)c++<< std::endl;
std::cout <<(int)c++<< std::endl;
std::cout <<(int)c++<< std::endl;return0;}
Attention que j'utilise enum class. Le code fonctionne bien enumaussi. Mais je préfère enum classcar ils sont fortement typés et peuvent nous empêcher de faire des erreurs au moment de la compilation.
Un vote négatif a été déposé sur ce post. Pourquoi ne répondrait-il pas à la question?
LAL
La raison en est probablement parce que c'est une terrible solution sur le plan architectural: elle vous oblige à écrire une logique globale destinée à un composant spécifique (votre énumération), de plus si votre énumération change pour une raison quelconque, vous êtes obligé de modifier votre + + opérateur aussi, comme une approche qui n'est durable pour aucun projet de moyenne à grande échelle, il n'est pas surprenant qu'elle provienne d'une recommandation de Bjarne Stroustrup, à l'époque l'architecture logicielle était comme de la science-fiction
Manjia
La question d'origine est d'avoir un opérateur sur un enum. Ce n'était pas une question architecturale. Je ne crois pas qu'en 2013 C ++ était une science-fiction.
LAL
1
Pour les compilateurs MS:
#define inc_enum(i)((decltype(i))((int)i +1))enum enumtype { one, two, three, count};for(enumtype i = one; i < count; i = inc_enum(i)){
dostuff(i);}
Remarque: c'est beaucoup moins de code que la réponse d'itérateur personnalisé simple.
Vous pouvez le faire fonctionner avec GCC en utilisant typeofau lieu de decltype, mais je n'ai pas ce compilateur à portée de main pour le moment pour être sûr qu'il compile.
Cela a été écrit ~ 5 ans après être decltypedevenu le C ++ standard, vous ne devriez donc pas recommander l' typeofancien du GCC. GCC vaguement récent gère decltypetrès bien. Il y a d'autres problèmes: les conversions de style C sont déconseillées et les macros pires. Les fonctionnalités C ++ appropriées peuvent donner les mêmes fonctionnalités génériques. Ce serait mieux réécrite à utiliser static_castet une fonction de modèle: template <typename T> auto inc_enum(T const t) { return static_cast<T>(static cast<int>(t) + 1); }. Et les lancers ne sont pas nécessaires pour les non enum class. Alternativement, les opérateurs peuvent être surchargés par enumtype (TIL)
underscore_d
1
typedefenum{
first =2,
second =6,
third =17}MyEnum;staticconstint enumItems[]={
first,
second,
third
}staticconstintEnumLength=sizeof(enumItems)/sizeof(int);for(int i =0; i <EnumLength; i++){//Do something with enumItems[i]}
Cette solution créera une variable inutilement statique en mémoire tandis que l'objectif d'énumération est juste de créer un «masque» aux constantes en ligne
TheArquitect
Sauf si changé enconstexpr static const int enumItems[]
Mohammad Kanan
0
C ++ n'a pas d'introspection, vous ne pouvez donc pas déterminer ce genre de chose au moment de l'exécution.
Pourriez-vous m'expliquer pourquoi une "introspection" serait nécessaire pour parcourir une énumération?
Jonathan Mee
Peut-être que le terme est la réflexion ?
kͩeͣmͮpͥ
2
J'essaie de dire 2 choses: 1) Pour de nombreuses autres réponses, C ++ peut accomplir cela, donc si vous dites qu'il ne le peut pas, un lien ou des clarifications supplémentaires sont nécessaires. 2) Dans sa forme actuelle, c'est au mieux un commentaire, certainement pas une réponse.
Jonathan Mee
Votez ma réponse alors - je pense que vous l'avez plus que justifiée
kͩeͣmͮpͥ
1
Je vais encore entasser 2 commentaires: 1) Je ne vote pas parce que je trouve que recevoir un vote négatif démotive la participation au site, je trouve cela contre-productif 2) Je ne comprends toujours pas ce que vous essayez de dire, mais cela ressemble à vous comprenez quelque chose que je ne comprends pas, auquel cas je préférerais que vous élaboriez plutôt que de supprimer une réponse votée.
Jonathan Mee
0
Si vous saviez que les valeurs d'énumération étaient séquentielles, par exemple l'énumération Qt: Key, vous pourriez:
Faites simplement un tableau d'entiers et faites une boucle sur le tableau, mais faites le dernier élément dire -1 et utilisez-le pour la condition de sortie.
Si enum est:
enumMyEnumType{Hay=12,Grass=42,Beer=39};
puis créez un tableau:
intArray[]={Hay,Grass,Beer,-1};for(int h =0;Array[h]!=-1; h++){
doStuff((MyEnumType)Array[h]);}
Cela ne se décompose pas, peu importe les chiffres de la représentation, tant que le contrôle -1 ne heurte pas l'un des éléments, bien sûr.
int
n'est peut-être pas assez important! ([C++03: 7.2/5]
)operator++
énumérations; cependant, vous pouvez donc le fairefor(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++)
. Notez que vous devez effectuer un cast0
versEnum_E
car C ++ interdit les opérateurs d'affectation sur les énumérations.Réponses:
La manière typique est la suivante:
Veuillez noter que l'énumération
Last
est destinée à être ignorée par l'itération. En utilisant cette "fausse"Last
énumération, vous n'avez pas à mettre à jour votre condition de terminaison dans la boucle for à la dernière "vraie" énumération chaque fois que vous souhaitez ajouter une nouvelle énumération. Si vous souhaitez ajouter d'autres énumérations plus tard, ajoutez-les simplement avant Last. La boucle dans cet exemple fonctionnera toujours.Bien sûr, cela tombe en panne si les valeurs d'énumération sont spécifiées:
Cela illustre le fait qu'une énumération n'est pas vraiment destinée à parcourir. La manière typique de traiter une énumération consiste à l'utiliser dans une instruction switch.
Si vous voulez vraiment énumérer, remplissez les valeurs d'énumération dans un vecteur et parcourez-le. Cela traitera également correctement les valeurs d'énumération spécifiées.
la source
UNKNOWN = 0
. De plus, je suggérerais simplement de supprimer ledefault
cas lors du basculement des valeurs d'énumération car cela pourrait masquer les cas où la gestion des valeurs a été oubliée jusqu'à l'exécution. Au lieu de cela, vous devez coder en dur toutes les valeurs et utiliser leUNKNOWN
champ pour détecter les incompatibilités.la source
static const Type All[3];
et alors je suis capable pour initialiser dans la source:const MyEnum::Type MyEnum::All[3] = { a, b, c };
Avant de faire cela, je recevais desError in range-based for...
erreurs odieuses (parce que le tableau avait une taille inconnue). Compris cela grâce à une réponse connexeSi votre énumération commence par 0 et l'incrément est toujours 1.
Sinon, je suppose que le seul pourquoi est de créer quelque chose comme un
ajouter les éléments et utiliser des itérateurs normaux ....
la source
Avec c ++ 11, il existe en fait une alternative: écrire un simple itérateur personnalisé basé sur des modèles.
supposons que votre énumération soit
Ce code générique fera l'affaire, assez efficacement - placé dans un en-tête générique, il vous servira pour toute énumération que vous pourriez avoir besoin de parcourir:
Vous devrez le spécialiser
Et puis vous pouvez itérer en utilisant range-for
L'hypothèse selon laquelle vous n'avez pas de lacunes dans votre énumération est toujours vraie; il n'y a aucune hypothèse sur le nombre de bits réellement nécessaires pour stocker la valeur d'énumération (grâce à std :: sous-jacent_type)
la source
std::vector
n'est pas générique parce questd::vector<foo>
c'est lié àfoo
.typedef Iterator<color, color::green, color::red> colorIterator;
Assurez-vous de comprendre le fonctionnement des instanciations de modèle.foo operator*() { ...
devrait l'êtreC operator*() { ...
.trop compliqué ces solution, j'aime ça:
la source
for (NodePosition pos : NodePositionVector)
syntaxe? Pour autant que je sache, il s'agit de la syntaxe Java, et vous aurez besoin d'itérateurs en C ++ pour faire quelque chose d'équivalent.auto
, vous n'avez donc pas à déclarer explicitement le type des éléments, sauf si vous (A) devez utiliser un opérateur de conversion ou (B) n'aimez pasauto
pour une raison quelconque . La plupart desfor
utilisateurs de laauto
gamme utilisent AFAICTJe le fais souvent comme ça
ou sinon successif, mais avec pas régulier (par exemple drapeaux de bits)
la source
Vous ne pouvez pas avec une énumération. Peut-être qu'un enum n'est pas le mieux adapté à votre situation.
Une convention courante consiste à nommer la dernière valeur d'énumération quelque chose comme MAX et à l'utiliser pour contrôler une boucle à l'aide d'un int.
la source
Quelque chose qui n'a pas été couvert dans les autres réponses = si vous utilisez des énumérations C ++ 11 fortement typées, vous ne pouvez pas les utiliser
++
ni les utiliser+ int
. Dans ce cas, une solution un peu plus compliquée est requise:la source
Vous pouvez essayer de définir la macro suivante:
Vous pouvez maintenant l'utiliser:
Il peut être utilisé pour parcourir en avant et en arrière à travers des entiers, des énumérations et des caractères non signés:
Malgré sa définition maladroite, il est très bien optimisé. J'ai regardé le désassembleur dans VC ++. Le code est extrêmement efficace. Ne vous découragez pas mais les trois pour les instructions: le compilateur ne produira qu'une seule boucle après optimisation! Vous pouvez même définir des boucles fermées:
Vous ne pouvez évidemment pas parcourir les types énumérés avec des lacunes.
la source
_A1
n'est pas un nom autorisé, c'est un trait de soulignement principal avec une majuscule suivante.Vous pouvez également surcharger les opérateurs d'incrémentation / décrémentation pour votre type énuméré.
la source
En supposant que l'énumération est numérotée séquentiellement, les erreurs sont sujettes. En outre, vous souhaiterez peut-être parcourir les énumérateurs sélectionnés uniquement. Si ce sous-ensemble est petit, le boucler explicitement pourrait être un choix élégant:
la source
Si vous n'aimez pas polluer votre énumération avec un élément COUNT final (car peut-être que si vous utilisez également l'énumération dans un commutateur, le compilateur vous avertira d'un cas manquant COUNT :), vous pouvez le faire:
la source
Voici une autre solution qui ne fonctionne que pour les énumérations contiguës. Il donne l'itération attendue, à l'exception de la laideur dans l'incrément, qui est à sa place, car c'est ce qui est cassé en C ++.
la source
foo = Bar(foo + 1)
.UNE
constexpr std::array
peut itérer même des énumérations non séquentielles sans que le tableau soit instancié par le compilateur. Cela dépend de choses comme l'heuristique d'optimisation du compilateur et si vous prenez l'adresse du tableau.Dans mes expériences, j'ai trouvé que
g++
9.1 avec-O3
optimisera le tableau ci-dessus s'il y a 2 valeurs non séquentielles ou pas mal de valeurs séquentielles (j'ai testé jusqu'à 6). Mais il ne fait cela que si vous avez uneif
déclaration. (J'ai essayé une instruction qui comparait une valeur entière supérieure à tous les éléments d'un tableau séquentiel et elle a aligné l'itération bien qu'aucun ne soit exclu, mais quand j'ai omis l'instruction if, les valeurs ont été mises en mémoire.) Elle a également inséré 5 valeurs d'une énumération non séquentielle dans [un cas | https://godbolt.org/z/XuGtoc] . Je soupçonne que ce comportement étrange est dû à une heuristique profonde liée aux caches et à la prédiction de branche.Voici un lien vers une simple itération de test sur godbolt qui montre que le tableau n'est pas toujours instancié.
Le prix de cette technique est d'écrire deux fois les éléments enum et de synchroniser les deux listes.
la source
Dans le livre du langage de programmation C ++ de Bjarne Stroustrup, vous pouvez lire qu'il propose de surcharger le
operator++
pour votre spécifiqueenum
.enum
sont des types définis par l'utilisateur et un opérateur de surcharge existe dans le langage pour ces situations spécifiques.Vous pourrez coder les éléments suivants:
code de test: http://cpp.sh/357gb
Attention que j'utilise
enum class
. Le code fonctionne bienenum
aussi. Mais je préfèreenum class
car ils sont fortement typés et peuvent nous empêcher de faire des erreurs au moment de la compilation.la source
enum
. Ce n'était pas une question architecturale. Je ne crois pas qu'en 2013 C ++ était une science-fiction.Pour les compilateurs MS:
Remarque: c'est beaucoup moins de code que la réponse d'itérateur personnalisé simple.
Vous pouvez le faire fonctionner avec GCC en utilisant
typeof
au lieu dedecltype
, mais je n'ai pas ce compilateur à portée de main pour le moment pour être sûr qu'il compile.la source
decltype
devenu le C ++ standard, vous ne devriez donc pas recommander l'typeof
ancien du GCC. GCC vaguement récent gèredecltype
très bien. Il y a d'autres problèmes: les conversions de style C sont déconseillées et les macros pires. Les fonctionnalités C ++ appropriées peuvent donner les mêmes fonctionnalités génériques. Ce serait mieux réécrite à utiliserstatic_cast
et une fonction de modèle:template <typename T> auto inc_enum(T const t) { return static_cast<T>(static cast<int>(t) + 1); }
. Et les lancers ne sont pas nécessaires pour les nonenum class
. Alternativement, les opérateurs peuvent être surchargés parenum
type (TIL)la source
constexpr static const int enumItems[]
C ++ n'a pas d'introspection, vous ne pouvez donc pas déterminer ce genre de chose au moment de l'exécution.
la source
Si vous saviez que les valeurs d'énumération étaient séquentielles, par exemple l'énumération Qt: Key, vous pourriez:
Cela fonctionne comme prévu.
la source
Faites simplement un tableau d'entiers et faites une boucle sur le tableau, mais faites le dernier élément dire -1 et utilisez-le pour la condition de sortie.
Si enum est:
puis créez un tableau:
Cela ne se décompose pas, peu importe les chiffres de la représentation, tant que le contrôle -1 ne heurte pas l'un des éléments, bien sûr.
la source