kzen.dev
  • Întrebări
  • Tag-uri
  • Utilizatori
Notificări
Recompense
Înregistrare
După înregistrare, veți primi notificări despre răspunsurile și comentariile la întrebările DVS.
Logare
Dacă aveţi deja un cont, autentificaţi-vă pentru a verifica notificările noi.
Aici vor fi recompensele pentru întrebările, răspunsurile și comentariile adăugate sau modificate.
Mai mult
Sursă
Editează
 Adam
Adam
Question

Cum pot repeta peste o enum?

Am observat că nu puteți utiliza standard de operatorii de matematica pe un enum astfel de ca ++ sau +=

Deci, ce este cel mai bun mod de a itera prin toate valorile într-un C++ enum?

279 2008-11-04T13:55:29+00:00 19
Lightness  Races with Monica
Lightness Races with Monica
Întrebarea editată 21 iunie 2013 в 10:04
Programare
c++
enums
Solution / Answer
andreas buykx
andreas buykx
4 noiembrie 2008 в 2:10
2008-11-04T14:10:51+00:00
Mai mult
Sursă
Editează
#8611709

Modul tipic este după cum urmează:

enum Foo {
  One,
  Two,
  Three,
  Last
};

for ( int fooInt = One; fooInt != Last; fooInt++ )
{
   Foo foo = static_cast<Foo>(fooInt);
   // ...
}

Vă rugăm să rețineți, enum "Ultima" este menit să fie sarit de repetare. Utilizând acest "fals" "Ultima" enum, nu't trebuie să actualizați de încheiere starea în buclă la ultima "reală" enum fiecare dată când doriți să adăugați un nou enum. Dacă doriți să adăugați mai multe enum mai târziu, doar adăugați-le înainte de Ultimul. Bucla în acest exemplu va funcționa în continuare.

Desigur, aceasta se descompune dacă enum valori sunt specificate:

enum Foo {
  One = 1,
  Two = 9,
  Three = 4,
  Last
};

Acest lucru ilustrează faptul că un enum nu este într-adevăr menit să repetăm. Modul tipic de a face cu un enum este să-l folosească într-un switch.

switch ( foo )
{
    case One:
        // ..
        break;
    case Two:  // intentional fall-through
    case Three:
        // ..
        break;
    case Four:
        // ..
        break;
     default:
        assert( ! "Invalid Foo enum value" );
        break;
}

Dacă doriți cu adevărat pentru a enumera, chestii enum valori într-un vector și repeta peste asta. Acest lucru se va face în mod corespunzător cu cele specificate enum valori la fel de bine.

David T&#243;th
David Tóth
Răspuns editat 4 octombrie 2019 в 1:37
246
0
 ZDF
ZDF
13 noiembrie 2014 в 2:07
2014-11-13T14:07:29+00:00
Mai mult
Sursă
Editează
#8611716
#include <iostream>
#include <algorithm>

namespace MyEnum
{
  enum Type
  {
    a = 100,
    b = 220,
    c = -1
  };

  static const Type All[] = { a, b, c };
}

void fun( const MyEnum::Type e )
{
  std::cout << e << std::endl;
}

int main()
{
  // all
  for ( const auto e : MyEnum::All )
    fun( e );

  // some
  for ( const auto e : { MyEnum::a, MyEnum::b } )
    fun( e );

  // all
  std::for_each( std::begin( MyEnum::All ), std::end( MyEnum::All ), fun );

  return 0;
}
 ZDF
ZDF
Răspuns editat 13 noiembrie 2014 в 2:45
42
0
Jo&#227;o Augusto
João Augusto
4 noiembrie 2008 в 2:20
2008-11-04T14:20:35+00:00
Mai mult
Sursă
Editează
#8611711

Dacă enum începe cu 0 și creștere este întotdeauna 1.

enum enumType 
{ 
    A = 0,
    B,
    C,
    enumTypeEnd
};

for(int i=0; i<enumTypeEnd; i++)
{
   enumType eCurrent = (enumType) i;            
}

Dacă nu, cred că doar de ce este de a crea ceva ca un

vector<enumType> vEnums;

adăugați elemente, și de a folosi normal iteratori....

18
0
Francesco Chemolli
Francesco Chemolli
5 august 2015 в 3:13
2015-08-05T15:13:41+00:00
Mai mult
Sursă
Editează
#8611717

Cu c++11, acolo este de fapt o alternativă: să scrie un simplu templatized personalizate iterator.

las's presupunem enum este

enum class foo {
  one,
  two,
  three
};

Acest cod generic va face truc, destul de eficient - loc într-un generic antet, l'll servi pentru orice enum ai putea avea nevoie pentru a repeta peste:

#include <type_traits>
template < typename C, C beginVal, C endVal>
class Iterator {
  typedef typename 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)) {}
  Iterator operator++() {
    ++val;
    return *this;
  }
  C operator*() { return static_cast<C>(val); }
  Iterator begin() { return *this; } //default ctor is good
  Iterator end() {
      static const Iterator endIter=++Iterator(endVal); // cache it
      return endIter;
  }
  bool operator!=(const Iterator& i) { return val != i.val; }
};

Te'll nevoie să se specializeze se

typedef Iterator<foo, foo::one, foo::three> fooIterator;

Și apoi puteți repeta folosind gama-pentru

for (foo i : fooIterator() ) { //notice the parentheses!
   do_stuff(i);
}

Presupunerea că tu nu't au lacune în enum este încă adevărat; nu există nici o presupunere privind numărul de biți de fapt nevoie pentru a stoca enum valoare (datorită std::underlying_type)

 darrenp
darrenp
Răspuns editat 17 mai 2019 в 9:47
17
0
 Enzojz
Enzojz
27 iulie 2014 в 3:56
2014-07-27T15:56:21+00:00
Mai mult
Sursă
Editează
#8611715

complicat prea mult aceste soluție, eu fac asa :

enum NodePosition { Primary = 0, Secondary = 1, Tertiary = 2, Quaternary = 3};

const NodePosition NodePositionVector[] = { Primary, Secondary, Tertiary, Quaternary };

for (NodePosition pos : NodePositionVector) {
...
}
14
0
Corey Trager
Corey Trager
4 noiembrie 2008 в 2:10
2008-11-04T14:10:23+00:00
Mai mult
Sursă
Editează
#8611708

Puteți't cu un enum. Poate un enum nu't cel mai potrivit pentru situația dumneavoastră.

O convenție comună este de a numi ultima enum valoare ceva de genul MAX și de a folosi că, pentru a controla o buclă folosind un int.

8
0
 Niki
Niki
18 ianuarie 2017 в 11:54
2017-01-18T11:54:09+00:00
Mai mult
Sursă
Editează
#8611721

Eu de multe ori fac asta

    enum EMyEnum
    {
        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))
    {}

sau dacă nu succesive, dar cu pas regulat (de exemplu, pic steaguri)

    enum EAnimal
    {
        E_First,
        E_None    = E_First,
        E_CanFly  = 0x1,
        E_CanWalk = 0x2
        E_CanSwim = 0x4,
        E_Last
    }

    for (EAnimali = E_First; i < E_Last; i = EAnimal(i << 1))
    {}
 Niki
Niki
Răspuns editat 8 ianuarie 2019 в 8:39
7
0
 Riot
Riot
13 iunie 2013 в 1:15
2013-06-13T01:15:40+00:00
Mai mult
Sursă
Editează
#8611714

Ceva care s't a fost acoperit în alte răspunsuri = dacă're folosind puternic tastat C++11 enum, nu puteți utiliza ++ sau + int pe ele. În acest caz, un pic mai dezordonat soluție este necesar:

enum class myenumtype {
  MYENUM_FIRST,
  MYENUM_OTHER,
  MYENUM_LAST
}

for(myenumtype myenum = myenumtype::MYENUM_FIRST;
    myenum != myenumtype::MYENUM_LAST;
    myenum = static_cast<myenumtype>(static_cast<int>(myenum) + 1)) {

  do_whatever(myenum)

}
6
0
Mikhail Semenov
Mikhail Semenov
9 decembrie 2011 в 10:04
2011-12-09T22:04:07+00:00
Mai mult
Sursă
Editează
#8611713

Puteți încerca și definiți următoarele macro:

#define for_range(_type, _param, _A1, _B1) for (bool _ok = true; _ok;)\
for (_type _start = _A1, _finish = _B1; _ok;)\
    for (int _step = 2*(((int)_finish)>(int)_start)-1;_ok;)\
         for (_type _param = _start; _ok ; \
 (_param != _finish ? \
           _param = static_cast<_type>(((int)_param)+_step) : _ok = false))

Acum puteți folosi:

enum Count { zero, one, two, three }; 

    for_range (Count, c, zero, three)
    {
        cout << "forward: " << c << endl;
    }

Acesta poate fi folosit pentru a repeta înainte și înapoi prin nesemnate, numere întregi, enum și caractere:

for_range (unsigned, i, 10,0)
{
    cout << "backwards i: " << i << endl;
}

for_range (char, c, 'z','a')
{
    cout << c << endl;
}

În ciuda ciudat definiție este optimizat foarte bine. M-am uitat la disassembler in VC++. Codul este extrem de eficient. Don't fi puse în afara, dar pentru trei declarații: compilatorul va produce doar o buclă după optimizare! Puteți defini chiar închise bucle:

unsigned p[4][5];

for_range (Count, i, zero,three)
    for_range(unsigned int, j, 4, 0)
    {   
        p[i][j] = static_cast<unsigned>(i)+j;
    }

Evident nu se poate repeta prin enumerate tipuri cu lacune.

6
0
 JohnMcG
JohnMcG
4 noiembrie 2008 в 5:35
2008-11-04T17:35:39+00:00
Mai mult
Sursă
Editează
#8611712

Puteți, de asemenea, supraîncărcați de incrementare/decrementare operatorii pentru tip enumerat.

3
0
 marski
marski
14 iulie 2019 в 12:17
2019-07-14T00:17:02+00:00
Mai mult
Sursă
Editează
#8611725

Presupunând că enum este numerotat secvențial este predispus la erori. Mai mult decât atât, poate doriți să itera peste selectate recenzorii numai. Dacă acest subset este mic, looping peste ea în mod explicit, ar putea fi o alegere eleganta:

enum Item { Man, Wolf, Goat, Cabbage }; // or enum class

for (auto item : {Wolf, Goat, Cabbage}) { // or Item::Wolf, ...
    // ...
}
2
0
Niels Holst
Niels Holst
30 mai 2016 в 7:32
2016-05-30T07:32:46+00:00
Mai mult
Sursă
Editează
#8611719

Dacă nu vă place să polueze ai enum cu un număr articol (pentru că poate dacă utilizați, de asemenea, enum într-un comutator, atunci compilatorul va avertiza de un caz de dispariție CONTA:), puteți face acest lucru:

enum Colour {Red, Green, Blue};
const Colour LastColour = Blue;

Colour co(0);
while (true) {
  // do stuff with co
  // ...
  if (co == LastColour) break;
  co = Colour(co+1);
}
2
0
Justin Moloney
Justin Moloney
17 iulie 2019 в 4:37
2019-07-17T04:37:30+00:00
Mai mult
Sursă
Editează
#8611726
typedef enum{
    first = 2,
    second = 6,
    third = 17
}MyEnum;

static const int enumItems[] = {
    first,
    second,
    third
}

static const int EnumLength = sizeof(enumItems) / sizeof(int);

for(int i = 0; i < EnumLength; i++){
    //Do something with enumItems[i]
}
1
0
 user2407277
user2407277
13 februarie 2016 в 11:35
2016-02-13T23:35:07+00:00
Mai mult
Sursă
Editează
#8611718

Pentru MS compilatoare:

#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); 
}

Notă: aceasta este o mulțime de cod mai puțin decât simpla templatized personalizate iterator răspuns.

Puteți obține acest lucru cu GCC, prin utilizarea typeof "în loc de" decltype`, dar eu nu't au compilator la îndemână în momentul de față pentru a vă asigura că compilează.

Benjamin W.
Benjamin W.
Răspuns editat 13 februarie 2016 в 11:56
1
0
Ethan Bradford
Ethan Bradford
8 noiembrie 2018 в 7:00
2018-11-08T19:00:28+00:00
Mai mult
Sursă
Editează
#8611723

Aici's o altă soluție care funcționează numai pentru învecinate enum. Acesta oferă așteptat iterație, cu excepția urâțenie în creștere, care este în cazul în care acesta face parte, din moment ce's ce's a rupt in C++.

enum Bar {
    One = 1,
    Two,
    Three,
    End_Bar // Marker for end of enum; 
};

for (Bar foo = One; foo < End_Bar; foo = Bar(foo + 1))
{
    // ...
}
Ethan Bradford
Ethan Bradford
Răspuns editat 8 noiembrie 2018 в 7:47
1
0
David Kemp
David Kemp
4 noiembrie 2008 в 2:12
2008-11-04T14:12:42+00:00
Mai mult
Sursă
Editează
#8611710

C++ nu't au introspecție, astfel încât să puteți't determina acest tip de lucru la run-time.

0
0
 Eponymous
Eponymous
27 mai 2019 в 9:17
2019-05-27T21:17:07+00:00
Mai mult
Sursă
Editează
#8611724

``c++ enum class A { a0=0, a3=3, a4=4 }; constexpr std::array<a, 3> ALL_A {A::a0, O::a3, O::a4}; // constexpr este important aici

pentru(a o: ALL_A) { if(a==O::a0 || o==O::a4) std::cout << static_cast(o); } ``

O constexpr std::array poate repeta chiar non-secvențială a enum fără matrice a fi instanțiată de compilator. Acest lucru depinde de lucruri cum ar fi compilatorul's de optimizare euristica și dacă luați matrice's adresa.

Din experimentele mele, am constatat că g++ 9.1 cu -O3 va optimiza departe de mai sus matrice dacă există 2 non-secvențială valori sau destul de câteva secvențială valori (am testat până la 6). Dar nu numai acest lucru, dacă aveți un "dacă" declarație. (Am încercat-o declarație pe care a comparat-o valoare întreagă mai mare decât toate elementele într-o matrice secventiala și inline repetare în ciuda niciunul fiind excluse, dar când am plecat la if, valorile au fost puse în memorie.) De asemenea, inline 5 valori de la un non-secvențială enum în [un caz|https://godbolt.org/z/XuGtoc]. Bănuiesc că acest comportament ciudat este cauza profundă euristici având de-a face cu cache-uri și sucursale de predicție.

Aici este un link-ul de la un simplu test de repetare pe godbolt care demonstrează matrice nu întotdeauna instanțiată.

Prețul acestei tehnici este scris enum elementele de două ori și păstrând cele două liste în sincronizare.

0
0
 kcrossen
kcrossen
31 iulie 2016 в 1:58
2016-07-31T13:58:29+00:00
Mai mult
Sursă
Editează
#8611720

Dacă ai ști că enum valorile au fost secvențiale, de exemplu Qt:Cheie enum, ai putea:

Qt::Key shortcut_key = Qt::Key_0;
for (int idx = 0; etc...) {
    ....
    if (shortcut_key <= Qt::Key_9) {
        fileMenu->addAction("abc", this, SLOT(onNewTab()),
                            QKeySequence(Qt::CTRL + shortcut_key));
        shortcut_key = (Qt::Key) (shortcut_key + 1);
    }
}

Acesta funcționează cum era de așteptat.

0
0
 mathreadler
mathreadler
15 martie 2018 в 9:51
2018-03-15T09:51:07+00:00
Mai mult
Sursă
Editează
#8611722

Doar asigurați-un tablou de int și bucla peste matrice, dar face ultimul element spun -1 și să-l utilizați pentru condiție de ieșire.

Dacă enum este:

enum MyEnumType{Hay=12,Grass=42,Beer=39};

apoi a crea matrice:

int Array[] = {Hay,Grass,Beer,-1};

for (int h = 0; Array[h] != -1; h++){
  doStuff( (MyEnumType) Array[h] );
}

Acest lucru nu se rupe în jos, indiferent de int în reprezentarea atâta timp cât -1 verificare nu se ciocnesc cu unul dintre elementele desigur.

-1
0
Adăugati o întrebare
Categorii
Toate
Tehnologii
Cultură
Viață / Artă
Stiință
Profesii
Afaceri
Utilizatori
Toate
Nou
Populare
1
工藤 芳則
Înregistrat 6 zile în urmă
2
Ирина Беляева
Înregistrat 1 săptămână în urmă
3
Darya Arsenyeva
Înregistrat 1 săptămână în urmă
4
anyta nuam-nuam (LapuSiK)
Înregistrat 1 săptămână în urmă
5
Shuhratjon Imomkulov
Înregistrat 1 săptămână în urmă
DE
ES
ID
JA
KO
RO
RU
TR
ZH
© kzen.dev 2023
Sursă
stackoverflow.com
în cadrul licenței cc by-sa 3.0 cu atribuire