views:

78

answers:

4

Hello!

I have an enum, that looks like this:

enum Suit {Clubs, Diamonds, Hearts, Spades};

I want to overload the increment operator, so I can easily loop over these four dudes.

When the variable is Clubs, Diamonds, or Hearts there no issue. Its the Spades condition that is giving me a little trouble.

My first instinct was to define it so that when the variable is spades, incrementation sets it equal to Clubs. The problem is that this seems to make it impossible to loop over the 4 values in the enum.

If I do something like

for(Suit i=Clubs;i<Spades;++i)
     {cout<<i<<endl;}

then my output only goes to Hearts.

If i do

for(suit i=Clubs;i<=Spades;++i)
    {cout<<i<<endl;}

then my output just loops forever!

So, I can obviously think of a few workarounds for this... I'm just not sure what the idiomatic C++ thing do to.

Should I redefine incrementation so that attempting to increment a Spade results in a Spade? or maybe throws an exception?

To reiterate: I can definitely think of a few hacky ways to fix this issue. I just want the guidance of experienced programmers to tell me what they think would be the most "normal" way to solve the problem.

+2  A: 

You could add enum values for start and termination conditions, and an alternative to ++ which doesn't cycle back to the beginning.

enum Suit { FirstSuit, Clubs = FirstSuit, Diamonds, Hearts, Spades, AllSuits };

for ( suit i = FirstSuit; i != AllSuits; i = iterate_suits( i ) )

Since for and while loops always check the condition before executing, there is no way to end their execution in the middle of a cyclic range without additional variables or flow control. A do while loop works best in this case.

Suit iter_suit = my_suit; // iterate over all suits beginning with my_suit.
do {
} while ( ++ iter_suit != my_suit );

In this case, you don't need FirstSuit and AllSuits.

Potatoswatter
Why should `operator++` never return AllSuits? Rather, shouldn't it throw when incrementing AllSuits?
UncleBens
this answer seems to make the most sense to me. I think defining operator+ differently is what I'm going to do
Alexander Questioning Bresee
@Uncle: OP seemed to be describing a modulo operation. No reason that should be invalid. It can also never return AllSuits, *and* throw when incrementing that value.
Potatoswatter
@Alexander: It occurred to me after posting that the overload of `operator+` needs `AllSuits` to be added just to have a valid return value. So then you might as well just use `AllSuits` (or `NumberOfSuits`, or whatever) as a constant.
Potatoswatter
What I don't understand is how ` i < AllSuits` would ever become false, if `i` always has one of the 4 smaller values. How is this different from `i <= Spades` never terminating the loop? Or do you propose giving unusual semantics to `operator<` as well? :)
UncleBens
I ended up just adding an extra value "End" in the enum, and defined x=Spades; ++x; to give x the value End... it works out kinda okay. Seems like there really should be a way to do this without breaking the wraparound suits.
Alexander Questioning Bresee
@Uncle: What the heck was I thinking???? It's bad to change an answer so much after it's been accepted, but now it's reasonable at least. I guess the downvote gods are smiling upon me today.
Potatoswatter
A: 

Perhaps

enum Suit {Clubs, Diamonds, Hearts, Spades, NumberOfSuits};

for(Suit i=Clubs;i<NumberOfSuits;++i)
 {cout<<i<<endl;}

There's still something unidiomatic (I have to know that Clubs is the first suit).

Why not just use the implicit conversion to int?

for (int i = 0; i < NumberOfSuits; ++i)
UncleBens
Well I guess I should've mentioned this, but I also have an overloaded << operator for the suit enum. I am aware that this is all very complicated for something so simple, but I'm really doing it as an OO exercise for myself. So, implicit int conversion wouldn't use my << operator. Also, I considered adding a member to my enum, but I thought that was inelegant. Of course I can do that if it turns out I need to. Also, sorry about the edit, I didn't expect "enter" to submit my post. I am a newbie here ;D
Alexander Questioning Bresee
+1  A: 

As suggested in a comment, what about just defining your enum as:

enum Suit {Clubs, Diamonds, Hearts, Spades, EndSuit};

Then your loop becomes:

for(Suit i=Clubs;i<EndSuit;++i)
{
    cout<<i<<endl;
}
Mark B
A: 

Since enum values decay into (unsigned) integers, you could use moduluo arithmetic and then cast back to an enum:

enum Suite add(const enum Suite card1, const enum Suite card 2)
{
 unsigned int result = card1;
 result += card2;
 result = result % 4;
 return (enum Suite) result;  // Casting shown for readability.
}

Suggestion: Make this into a class. With a class you can also add "print" and "input" methods.

Thomas Matthews