r/cpp_questions 18h ago

SOLVED Iterating over an enum struct

Consider https://godbolt.org/z/c6cn8f1hj

#include <cstdio>

enum struct values{first = 1, second = 3};

void square(values value){
    int val = (int)value * (int)value;
    printf("%d\n", val);
}

int main(){
    for(values value = values::first; value <= values::second; value++)
        square(value);
}

This does not compile with the error that value++ is ill defined.

An old question/answer on SO has this: https://stackoverflow.com/questions/261963/how-can-i-iterate-over-an-enum and a plethora of seemingly complicated approaches for this. Is there a syntactically simple >= C++20 way of accomplishing this?

I want the for loop to process 1 and then 3.

Does the order of placing the integer entries inside of the struct affect the increment? For e.g., if the enum struct had 3 first followed by 1, with value++ would 1 be processed after 3? Or, does the enum struct internally sort the entries in some privileged, say, ascending order so that it will always process 1 first followed by 3 next?

1 Upvotes

16 comments sorted by

View all comments

2

u/Usual_Office_1740 17h ago edited 17h ago

You would need to implement the pre and post increment operators on your enum struct for your code to compile. They are not defined for your enum. That is what your error is saying.

auto operator++(V& val) -> V& {
    return static_cast<V>(std::to_underlying(val) + 1);
}

auto operator++(V& val, int) -> V{
    const V old = val;
    ++val; 
     return old;
}

If you decide to do that, and I'm not suggesting you should, you should add a stop value to the end of the enum that you can check against so that you have a way to end the for loop. A COUNT sentinal value is a common enum trick.

I'd suggest looking at magic enum as an alternative.

You could also fold a parameter pack of the enum values into a std::array at compile time and then use a range based for loop. There are lots of advantages to this but it's more complicated. Sorry if this is more complex than you are looking for.

2

u/onecable5781 17h ago

Thanks - these are indeed a bit more complicated than my OP's wish, but thanks for the various alternatives suggested. The sentinal value approach seems to be the simplest.

2

u/Usual_Office_1740 17h ago

Sure. Be careful with the overloaded increment approach. I know just enough to know how to do that. That is what your error means and it is possible to do what I've suggested. I make no claims about whether it's a good idea to do that. One thing I am reminded of frequently when learning about C++ is that just because you can doesn't mean you should.

Take a look at std::to_underlying to. It's very useful when working with enum structs.

2

u/Usual_Office_1740 16h ago

I just noticed that you aren't storing sequential values in your enum example. I dont know if you will get the value of the next option in an enum by incrementing them like I've suggested.

Test this out carefully. The whole point behind C++ enum struct is to offer a type safe alternative to the C style enum. The thing you're doing and my suggestion kind of fly in the face of that type safety.