What is the best data structure for storing a fixed length collection of named constants that can be used in a switch without explicit casting?

Viewed 79

What is the best data structure for storing a fixed length collection of named constants that can be used in a switch without explicit casting?

I want to write clean code that looks like this:

   enum class EventType : uint8_t{
      NOTE_ON = 9,
      NOTE_OFF = 8,
      CONTROL_CHANGE = 11,
      CHANNEL_PRESSURE = 13,
      PITCH_WHEEL_CHANGE = 14
   };

   // Sometime later in a function scope:
   using enum EventType;
   switch(((Status & 0xF0)>>4)){
         case NOTE_OFF:
            std::cout << "NOTE OFF: " << std::endl;
         break;
         case NOTE_ON:
            std::cout << "NOTE ON: " std::endl;
         break;
         case CONTROL_CHANGE:
            std::cout << "CONTROL CHANGE: " <<std::endl;           
         break;
         case CHANNEL_PRESSURE: 
            std::cout << "CHANNEL PRESSURE: " <<std::endl;
         break;
         case PITCH_WHEEL_CHANGE:
            std::cout << "PITCH WHEEL CHANGE: " << std::endl;
         break;
         default:
            std::cout << "UNKNOWN EVENT TYPE: " << <<std::endl;
   }

But there doesn't seem to be a way to use an enum class in a switch without explicitly casting the value to an int in every single case statement which is very verbose and defeats the point of using clean, easy to read labels.

Is there a better data container choice for this?

Criteria:

  • The number and length of items in the container is fixed and known at compile time.
  • The contents will never change at run time.
  • The text labels do not need to be displayed or printed out.
  • Data should be in some type of collection to avoid namespace pollution.
  • The goal is to have a set of human-readable labels on switch cases, if, etc.
  • The labels should be usable with the least verbosity possible to keep the code clean. ie. no need to explicitly cast it or call a member function to extract something.
3 Answers

Cast the condition for the switch to the enumeration type:

switch(static_cast<EventType>((Status & 0xF0)>>4)) {…}

Define an accessor for the event part of the status (and do this for the other parts as well):

EventType event(int status) 
{ 
    return static_cast<EventType>((status & 0xF0) >> 4); 
}

and then

switch(event(Status)){
     case EventType::NOTE_OFF:
     ...

You can define shift and bitwise operators for your enum class:

inline EventType operator&(EventType a, std::uint8_t b)
    { return EventType(std::uint8_t(a) & b); }

inline EventType operator>>(EventType a, std::uint8_t s)
    { return EventType(std::uint8_t(a) >> s); }
Related