2013-06-20 11 views
15

Jaka jest preferowana metoda prosta do iteracji poprzez wyliczenie z sąsiadującymi wartościami w C++? Znalazłem poprzednie pytania na ten temat dotyczące SO, które dotyczyły tworzenia niestandardowych operator++ itp., Ale wydaje się to przesadą. Do tej pory najlepszym Mam wymyślić to:Najprostsza metoda do iteracji poprzez ciągłe wartości wyliczeniowe w C++

enum { 
    FOO, 
    BAR, 
    BLECH, 
    NUM_ENUMS 
} MyEnum; 

//for (MyEnum m = FOO; m < NUM_ENUMS; ++m)    // compile error 
// ... 

//for (MyEnum m = FOO; m < NUM_ENUMS; m = m + 1)  // compile error 
// ... 

for (MyEnum m = FOO; m < NUM_ENUMS; m = MyEnum(m + 1)) // OK ? 
    ... 

Czy to rozsądne z punktu widzenia stylu kodowania i jest prawdopodobne, aby generować ostrzeżenia (g++ -Wall ... wydaje się zadowolony z tego)?

+5

Może to kwestia strona dlaczego chcesz iterować po enumie, a jeśli naprawdę, czy istnieje lepszy sposób na przedstawienie nazwanych wartości do iteracji? Co powiesz na używanie kontenera std :: map – woosah

+2

Jest to dobre, o ile nie definiujesz niestandardowych wartości dla elementów, pozostawiając spacje między nimi (np .: FOO = 1, BAR = 5, BLECH = 7) – dunadar

+1

Twoja trzecia próba powinna być ok (patrz [ta odpowiedź] (http://stackoverflow.com/a/261986/237483)) –

Odpowiedz

14

Jest rzeczywiście bezpieczny.

Nie zostałoby to zdefiniowane: MyEnum(int(NUM_ENUMS) + 1), ponieważ wartość do zawieszenia (4) byłaby większa niż wartość wyliczenia ([0, 3]); ponieważ zapewniasz, że m jest ściśle niższa niż NUM_ENUMS, można bezpiecznie używać MyEnum(m + 1).

Z drugiej strony należy pamiętać, że masz problemy z dostosowanymi teksty stałe, takie jak:

enum OtherEnum { 
    Foo = -1, 
    Bar = 2, 
    Baz = 8, 
    NUM_OTHERENUM 
}; 

więc nie jest to ogólna praktyka.

Radziłbym wygenerowany tablicę iteracyjne nad zamiast:

MyEnum const Values[] = { FOO, BAR, BLECH }; 

Należy pamiętać, że jest ona łatwo generowane z definicji wyliczenia, a także uniknąć zanieczyszczenia interfejs o wartości nonsensowny (business-wise) .

+0

Dzięki - zaktualizowałem pytanie, aby wyjaśnić, że moje wymagania dotyczą wyłącznie przylegających wartości wyliczeniowych. –

1

Tak jak Matthieu powiedział, że jest to całkowicie bezpieczne i nie jest w żaden sposób sprzeczne ze standardem C++.

marginesie przeciążenia ++ operatora nad enum jest nie tylko przesada, ale ma problemy już wspomniano przez innych (np jeśli enum nie jest liniowa w wartościach)

Dlatego zamiast definiowania operatora ++ potrzebujesz iteratora.

Zaadaptowałem następujące rozwiązanie tutaj: regarding enums przez deft_code, ale nieco dostosowane do Twojego przykładu.

template< typename T > 
class Enum 
{ 
public: 
    class Iterator 
    { 
    public: 
    Iterator(int value) : 
    m_value(value) 
    { } 

    T operator*(void) const 
    { 
    return (T)m_value; 
    } 

    void operator++(void) 
    { 
    ++m_value; 
    } 

    bool operator!=(Iterator rhs) 
    { 
    return m_value != rhs.m_value; 
    } 

    private: 
     int m_value; 
    }; 

}; 

template< typename T > 
typename Enum<T>::Iterator begin(Enum<T>) 
{ 
    return typename Enum<T>::Iterator((int)T::First); 
} 

template< typename T > 
typename Enum<T>::Iterator end(Enum<T>) 
{ 
    return typename Enum<T>::Iterator(((int)T::Last) + 1); 
} 

enum class MyEnum 
{ 
    FOO, 
    BAR, 
    BLECH, 
    NUM_ENUMS 
}; 

int main() 
{ 
    for(auto e: Enum<MyEnum>()) 
    { 
     std::cout << ((int)e) << std::endl; 
    } 
} 

Może to nadal być przesada dla Ciebie, ale jest znacznie czystsza. Kolejny kawałek kodu, ale o wiele bardziej eleganckie podejście to here. Możliwe jest, że w przyszłości klasy wyliczeniowe wprowadzone w C++ 11 mogą mieć iterator w standardzie.

Aktualizacja: (?) Ponieważ informować nas, że wartości są ciągłe i fakt, że jest to konieczne dla C API to powyższe nie będą odpowiednie

+0

Dzięki - rzeczy w C++ 11 są interesujące, ale moje wyliczenie jest zdefiniowane jako część C API, która musi być wywołana z uprzęży testowej C++, więc muszę pracować ze zwykłym starym Cumem (choć w kontekście C++). –

+0

@woosah Podany link wydaje się być martwy. – ZeroPhase

Powiązane problemy