简体   繁体   中英

Compile-time assert when not all enum values are handled in a switch statement in C++

I'd like to get a compiler warning or error when not all possible enum values are handled in a switch statement. Of course I can add a default case with an assert and (eventually) get an error at runtime. But I'd like to get an error at compile-time.

I'm not sure if this is possible at all with C++, but maybe someone knows a trick...

Edit: Using -Wswitch seems to be the solution for GCC. Is there something similar for VS2010? (I'm not using GCC).

Edit2: Ok, I found the solution for VC++ (VS2010):

Enabling warning C4062 produces a warning when a value is missing und no default case is provided.

Enabling warning C4061 produces a warning when a value is missing, even if a default case is provided.

You haven't mentioned which compiler you're using. If you're using GCC, you can get that for free simply by enabling -Wswitch (which is automatically enabled by -Wall ).

If you are using g++, with -Wall , then you will get it.

For example, this :

enum Abc
{
  A =1,
  B,
  C
};

Abc a = A;
switch( a )
{
 case A:
  break;
 case B:
  break;
}

is going to cause a warning.

But it is better to use default case with failed assertion, because when you add a new enum value, you have to change all the files where you are using switch on this enum.

AFAIK there's no conventional way to achieve what you want with MSVC. There're tricks to do similar things, but they involve either a sophisticated template voodoo, or really fierce macros riddles.

For example, instead of defining your enum in a conventional way do the following:

#define MyEnumEntries(m) \
    m(A, 1) \
    m(B, 2) \
    m(C, 3) \

enum Abc {

    // the following will expand into your enum values definitions
#   define M_Decl(name, value) name = value,
    MyEnumEntries(M_Decl)
};

Now, your switch can be rewritten into this:

Abc a = A;

switch( a )
{
#define M_Goto(name, value) \
case value:
    goto label_##name;

MyEnumEntries(M_Goto)


case label_A:
    // TODO
    break;
case label_B:
    // TODO
    break;
}

The above will not compile if you won't add the switch entry label_... for all the enum values.

Been trying to solve a similair problem, Id like to elaborate on the answers above

Previous answers by:

  • Oliver Charlesworth
  • BЈовић
  • TonyK

(9 years late, Sorry 😕| Maybe I'll help some other C++ newby out there)


If you have a switch statement like such:

switch (EnumClass){
   case EnumA: do_something();   return;
   case EnumB: do_other_thing(); return;
   .
   .
   case EnumZ: last_do_thing();  return;
}

GCC can be your greatest friend and can catch these issues for you when something is changed in the enumerator.

The key here is theCompile-Time warning-options , specifically the:

  • -Wswitch (Warns for un-handled Enum values IF there isnt a default in the switch)
  • -Wswitch-default (Warns if there isnt a default in a switch statement)
  • -Wswitch-enum (Same as -Wswitch , but warns even if there is a default in the switch)

As Mentioned above, the -Wall option includes the -Wswitch option, but not the other 2, so those have to be individual


Now, these arent very useful if somebody else modifies your code and compiles it without the flag... SO

You may want to use #pragma statements to force the check.

#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wswitch"

enum EnumClass{
   EnumA,
   EnumB,
   .
   .
   EnumZ,
}

EnumClass EnumVal = EnumA;

switch (EnumVal){
   case EnumA: //Something
   case EnumB: //Other Thing
   .
   .
   case EnumZ: //Final Thing
}

#pragma GCC diagnostic pop

What do these pragma statments mean? Good question! reference for below info

#pragma GCC diagnostic push

This statement tells GCC to take note of the existing warning configuration (either set by the command line call to GCC, or by other #pragma statements earlier in the code)

#pragma GCC diagnostic error "-Wswitch"

This statement tells GCC to throw a compile Error whenever a -Wswitch violation is found. (overrides the command line option and previous #pragma)

#pragma GCC diagnostic pop

This statement restores the compile settings to the most recent push , in this case, the one we did earlier.

These #pragma statements are useful for all sorts of stuff, with limitations loosely noted in the documentation


In Summary

Use -Wswitch in the command line to check to make sure enums are all handled (or default exists to handle them).

If you want GCC to check without having to use the flag manually, use #pragma GCC diagnostic error "-Wswitch"

Good Luck!

如果您使用-Wall启用所有警告,g++ 会自动执行此操作。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM