How awful is it - or is it perfectly acceptable - to index a loop on an enumeration?
I have an enumeration defined. The values of the literals are default values. The assigned values do not have any significance, will not have any significance, and the values of any literals added in the future will also not have any significance. It's just defined to limit the allowed values and to make things easier to follow. Therefore the values will always start at 0 and increase by 1.
Can I set up a loop like so:
enum MyEnum
{
value1,
value2,
value3,
maxValue
}
for(MyEnum i = value1; i < maxValue; i = static_cast<MyEnum>(i+1)){}
Yes. Use GetValues() method in System. Enum class.
Can you loop through an enum C ++? Yes. It iterates over an std::initializer_list<Item>.
An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying integral numeric type. To define an enumeration type, use the enum keyword and specify the names of enum members: C# Copy.
I wrote an enum iterator a while ago for these cases
enum Foo {
A, B, C, Last
};
typedef litb::enum_iterator<Foo, A, Last> FooIterator;
int main() {
FooIterator b(A), e;
std::cout << std::distance(b, e) << " values:" << std::endl;
std::copy(b, e, std::ostream_iterator<Foo>(std::cout, "\n"));
while(b != e) doIt(*b++);
}
If you are interested, here is the code. If you like, you can extend it to be a random access iterator by providing +
, <
, []
and friends. Algorithms like std::distance
will thank you by providing O(1)
time complexity for the then random-access iterator.
#include <cassert>
namespace litb {
template<typename Enum, Enum Begin, Enum End>
struct enum_iterator
: std::iterator<std::bidirectional_iterator_tag, Enum> {
enum_iterator():c(End) { }
enum_iterator(Enum c):c(c) { }
enum_iterator &operator=(Enum c) {
this->assign(c);
return *this;
}
enum_iterator &operator++() {
this->inc();
return *this;
}
enum_iterator operator++(int) {
enum_iterator cpy(*this);
this->inc();
return cpy;
}
enum_iterator &operator--() {
this->dec();
return *this;
}
enum_iterator operator--(int) {
enum_iterator cpy(*this);
this->dec();
return cpy;
}
Enum operator*() const {
assert(c != End && "not dereferencable!");
return c;
}
bool equals(enum_iterator other) const {
return other.c == c;
}
private:
void assign(Enum c) {
assert(c >= Begin && c <= End);
this->c = c;
}
void inc() {
assert(c != End && "incrementing past end");
c = static_cast<Enum>(c + 1);
}
void dec() {
assert(c != Begin && "decrementing beyond begin");
c = static_cast<Enum>(c - 1);
}
private:
Enum c;
};
template<typename Enum, Enum Begin, Enum End>
bool operator==(enum_iterator<Enum, Begin, End> e1, enum_iterator<Enum, Begin, End> e2) {
return e1.equals(e2);
}
template<typename Enum, Enum Begin, Enum End>
bool operator!=(enum_iterator<Enum, Begin, End> e1, enum_iterator<Enum, Begin, End> e2) {
return !(e1 == e2);
}
} // litb
As far as I'm concerned, that's just fine. I'm sure some purist out there somewhere will freak out, but as far as the language spec is concerned, that code will work correctly, so you should feel free to go for it if it makes your life easier.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With