user3195869
user3195869

Reputation: 95

How to overload the << operator for enums

I'm trying to write a generic template overload for the bitswise << operator, but I'm having a hard time specifying that the left side of the operator is an enum, and the compiler gives me an 'ambiguous overload' error.

I'd hope that the static_assert would tell the compiler that the << operator in "file << x" is not the template I've defined, and it would then pick up the << operator defined in iostream. But, I get a compiler message saying that the two are ambiguous.

It does not have this issue with "cout << x".

  #include <fstream>
  #include <iostream>
  using namespace std;

  enum DAY{MON=1,TUES=2,WED=4,THUR=8,FRI=16};

  template<typename Enum>  
  constexpr Enum operator <<(Enum e,int n)  
  {
    static_assert(std::is_enum<Enum>::value, 
    "template parameter is not an enum type");

    using underlying = typename std::underlying_type<Enum>::type;
    return static_cast<Enum> ( static_cast<underlying>(e) << n );
  }

  int main()
  {
  // this does as I'd like
    DAY day = MON;
    day = static_cast<DAY>(day << 2); // this is the behavior I need
    cout << day << endl;

// but this is ambiguous
    ofstream file("test.dat");
    float x;
    file << x; // this line is ambigous
    return 0;
  }

Upvotes: 0

Views: 366

Answers (1)

Miles Budnek
Miles Budnek

Reputation: 30494

static_assert applies too late to remove your operator<< from overload resolution. You need to use SFINAE instead. Something like this will do what you want:

template <typename Enum>
constexpr std::enable_if_t<std::is_enum_v<Enum>, Enum>
operator<<(Enum e, int n)
{
    using underlying = typename std::underlying_type_t<Enum>;
    return static_cast<Enum> ( static_cast<underlying>(e) << n );
}

Live Demo

Upvotes: 3

Related Questions