Transisiton from "enum" to "enum class"

hey i am a newbie to arduino coding.

in my code i used enum and a switch case of the enum to cycle through different program states. this is the code:

enum BootSequence {
  bootPhase0,
  bootPhase1,
  bootPhase2,
  bootPhase3,
};
BootSequence WandStartSequence = bootPhase0;

bool PROGRAM_BOOTING() {
  switch (WandStartSequence) {
    case bootPhase0:
      PROGRAM_BOOT_BLINK_L();
      break;

    case bootPhase1:
      PROGRAMM_BOOT_KL();
      break;

    case bootPhase2:
      PROGRAM_Vent_bootUp();
      break;

    case bootPhase3:
      BLINK_FUNCTION_LED_OF_SEGMENT(BarGraph_Segment, 0);
      break;
  }
  if(WandStartSequence == bootPhase3){
    Serial.println("Booted");
    return true;
  }
  else{
    Serial.println("NOT Booted");
    return false;
  }
}

and in the loop function for debugging this:

Serial.println(WandStartSequence);

Then i switched to the newer enum class. But I cannot print the current value neither as string nor as int. Do i have to convert them?

And another question is that i am also using a soundchip for playing music in my program. the soundchip plays the tracks according to the provided number as int.
i there a way that i can assign the tracknames as enum class like ambient = 1, idle = 5, ....
and the use this variables for better readability? like playSong(idle), instead of playSong(5)?

enum class BootSequence {
  bootPhase0,
  bootPhase1,
  bootPhase2,
  bootPhase3,
};

BootSequence WandStartSequence = BootSequence::bootPhase0;




//switch function with functions above
bool PROGRAM_BOOTING() {
  switch (WandStartSequence) {
    case BootSequence::bootPhase0:
      PROGRAM_BOOT_BLINK_L();
      break;

    case BootSequence::bootPhase1:
      PROGRAMM_BOOT_KL();
      break;

    case BootSequence::bootPhase2:
      PROGRAM_Vent_bootUp();
      break;

    case BootSequence::bootPhase3:
      BLINK_FUNCTION_LED_OF_SEGMENT(BarGraph_Segment, 0);
      break;
  }
  if(WandStartSequence == BootSequence::bootPhase3){
    Serial.println("Booted");
    return true;
  }
  else{
    Serial.println("NOT Booted");
    return false;
  }
}



void loop() {



  Serial.println(WandStartSequence); //-> not working
[... more code]
}

So in short:

  • How can I Serial print the current text value of my enum class.
  • Can i assign the enum class variables different ints like in the old enum?
  • Can I convert a class enum into an int

If a normal enum does what you want then why not use that? What's the purpose of the change?

Why did you do this ?

Cast it to an int

Have you tried?

Why would you want to do that?

As I wrote the soundchip member functions take an int as input.
In this way I can organize my soundfiles on top of my scetch with readable names and when i want to play them later i assign the name to the memeberfunction which hopefully gets converted to an int, so that the function can play the corresponding track.

Because it doesn't work the way you want it to. Why not use the thing that actually works instead of worrying about something you read and didn't understand.

read about that it is saver to use the enum class, because of not messing up with namespaces for example. and i am just learning c++ so why not use the current stuff instead of older?

you need to cast the enumeration class, then you can print the value (or hand it over to another function).

/*
    https://forum.arduino.cc/t/transisiton-from-enum-to-enum-class/1284063
    
 */

enum class BootSequence {
  bootPhase0,
  bootPhase1,
  bootPhase2,
  bootPhase3,
};

BootSequence WandStartSequence = BootSequence::bootPhase0;

void PROGRAM_BOOT_BLINK_L() {}
void PROGRAMM_BOOT_KL() {}
void PROGRAM_Vent_bootUp() {}

void BLINK_FUNCTION_LED_OF_SEGMENT(int a, int b){
  (void)a;
  (void)b;
}

int BarGraph_Segment;

//switch function with functions above
bool PROGRAM_BOOTING() {
  switch (WandStartSequence) {
    case BootSequence::bootPhase0:
      PROGRAM_BOOT_BLINK_L();
      break;

    case BootSequence::bootPhase1:
      PROGRAMM_BOOT_KL();
      break;

    case BootSequence::bootPhase2:
      PROGRAM_Vent_bootUp();
      break;

    case BootSequence::bootPhase3:
      BLINK_FUNCTION_LED_OF_SEGMENT(BarGraph_Segment, 0);
      break;
  }
  if (WandStartSequence == BootSequence::bootPhase3) {
    Serial.println("Booted");
    return true;
  }
  else {
    Serial.println("NOT Booted");
    return false;
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println((int)WandStartSequence); // cast to make it printable
}

void loop() {
  Serial.println((int)WandStartSequence); 
}

P.S.: please always provide a full sketch - otherwise we can't put it in the IDE and make it working.

btw, I think there are better names like "phase 0 .. phase 3".

You are unable to print the enum class because there is no overload of the print class for the enum class.

1 Like

Hey thank you.
Is there a fundamental difference between? your Version and static cast like:

  int temp_int = static_cast<int>(WandStartSequence);
  Serial.println(temp_int);

:slight_smile: any suggestions?

if you prefer the static_cast - use the static cast.

Doing so is a recognized C++ Best Practice.

1 Like

On the why = in C++, an enum allows for implicit promotion to its underlying integral type, typically an int, for compatibility with C. This means that values of an enum type can be used interchangeably with integers in expressions, assignments, and function arguments without requiring an explicit cast.

However, an enum class (strongly-typed enumeration) introduced in C++11 does not allow such implicit promotion. Enum class values are strongly scoped and must be explicitly cast to their underlying type to be used as integers. This design choice was made to enhance type safety by preventing unintended conversions and limiting the scope of enumerators.

So your issue (as other explained) was that you did no longer benefit from the implicit promotion to an int which print would know how to handle.

1 Like

So if you're going to cast them everywhere anyway then it really doesn't bring much benefit does it? It sounds like it just creates extra syntax in this case.

well - the point is that you should not cast them.

if you want to print

enum class BootSequence {
  bootPhase0,
  bootPhase1,
  bootPhase2,
  bootPhase3,
};

then you write

void printBootSequence(BootSequence phase) {
  switch (phase) {
    case BootSequence::bootPhase0: Serial.print(F("bootPhase0")); break;
    case BootSequence::bootPhase1: Serial.print(F("bootPhase1")); break;
    case BootSequence::bootPhase2: Serial.print(F("bootPhase2")); break;
    case BootSequence::bootPhase3: Serial.print(F("bootPhase3")); break;
    default: Serial.print(F("Unknown BootSequence phase")); break;
  }
}
1 Like

But OP read about something that said it was safer. Now they want it to work the unsafe way. If OP is ok with the cast then what's the point of using the enum class? If OP wants an enum class then he shouldn't be trying to make it an int.

so the function to print the enumerator is the "safe way" we should show :slight_smile:

if OP wants a cast then there is no point in using enum class, just sticking to plain old enum and implicit promotion is good enough.

1 Like

enum class allows multiple enum types to use the duplicate member names without conflict. The same names can even have different underlying integer values in different enum classes.

2 Likes

I did forget that that is the reason why I use them :frowning: