Arvind Swami
Arvind Swami

Reputation: 123

How to overload the ++ operator for a enum in C++

This is what I tried, but I see that overloading only increments the variable if I assign it to another variable. I.e, The value of the variable on which I do the increment does not increase. So, in the example below variable newDay is THU but currentDay remains WED.

How do I define the overload operator to increment variable I am doing the operation on?

typedef enum days {MON, TUE, WED, THU, FRI, SAT, SUN} days;

inline days operator++ (days& d) {
    return static_cast<days>((static_cast<int>(d) + 1) % 7);
}

int main(int argc, const char * argv[]) {
   days currentDay = WED;
   days newDay = ++currentDay;
   cout << "Current day: " << currentDay << ", Stored day: " << calendar[0] << ", New day: " << newDay << endl;
}

Upvotes: 6

Views: 7366

Answers (3)

bobobobo
bobobobo

Reputation: 67224

First, I wouldn't recommend you overload operator++ to have the enum cycle.

This could easily cause a hang if you have a loop like:

for( days d = MON; d <= SUN; d++ ) {
  // hangs
}

It's really unexpected in C++ that operator++ cycles. Consider using a C++ function like this, so it's 100% clear from the code that the enum will cycle

template <typename E>
inline E& cycleEnum( E &val, E minVal, E maxVal ) {
  int e = (int)val;
  if( ++e > maxVal )
    e = minVal;
  return val = (E)e;
}

Use:

days day = MON;
cycleEnum( day, MON, SUN );

Defining operator++ for enums

I have seen this done with a macro before

This only defines pre & post increment, but you could define bitwise ops too (though you probably shouldn't define increment and bitwise on the same enum class)

#include <map>
#include <string>
using std::map, std::string;

enum class MouseButton {
  Left,
  Middle,
  Right,

  NUM_BUTTONS
};

#define PRE_AND_POST_INCREMENT( ENUM )                        \
inline ENUM& operator++( ENUM& enumVal ) {                    \
  return (ENUM&)(++(int&)enumVal);                            \
}                                                             \
                                                              \
inline ENUM operator++( ENUM& enumVal, int postIncrement ) {  \
  ENUM oldValue = enumVal;                                    \
  ++enumVal;                                                  \
  return oldValue;                                            \
}                                                             \
  
PRE_AND_POST_INCREMENT( MouseButton )

map< MouseButton, string > mouseButtonName = {
  { MouseButton::Left, "Left" },
  { MouseButton::Middle, "Middle" },
  { MouseButton::Right, "Right" },
};

int main() {

  for( MouseButton mb = MouseButton::Left; mb < MouseButton::NUM_BUTTONS; mb++ ) {
    puts( mouseButtonName[ mb ].c_str() );
  }
  
}

There is also this template approach which you could adapt for operator++ (warning: it modifies all enums to act like an int!)

Upvotes: 0

If I modify your overloaded operator to this:

inline days operator++ (days const& d) {
    return static_cast<days>((static_cast<int>(d) + 1) % 7);
}

It still compiles, despite the fact I added a const specifier there. That's because you are not modifying d like the semantics of prefix ++ demand.

So make sure you do modify it, if you want the operator to have the desired effect:

inline days operator++ (days& d) {
    d = static_cast<days>((static_cast<int>(d) + 1) % 7);
    return d;
}

Without commenting on the validity of your own design, note that it is a widely held opinion that prefix operator++ should return a modifiable lvalue, like the built-ins do. Bear in mind if you find yourself writing code like ++x = y, you need to return a reference, i.e. date& operator++(date&).

Upvotes: 3

Johnathan Gross
Johnathan Gross

Reputation: 678

You defined the postfix operator. The normal behavior of the postfix operator is to increment the value of its argument but return the original value. It should behave like this:

days operator++(days& d,int){
    days temp=d;
    d=static_cast<days>((static_cast<int>(d) + 1) % 7);
    return temp;
}

What you want is the prefix operator. This increments the value of the argument and returns a reference to its arguments. It should look like this:

days& operator++(days& d){
    d=static_cast<days>((static_cast<int>(d) + 1) % 7);
    return d;
}

Upvotes: -1

Related Questions