Default case compilation when switching over all items of an enum class - c++

Why does the following switch even compiles the default case since it covers all items of the enum class?
I would have thought that this was the reason for having strong enum class in the first place.
As to why I would like to have a default even though I know that I cover all cases : This safe-guards me against my future careless-ness (and that of other coworkers)
enum class E {
a,
b
};
int main()
{
E c = E::b;
switch (c) {
case E::a:
case E::b:
std::cout << "pass" << std::endl;
break;
default:
static_assert(false, "This explodes!");
}
}
Proof

Because the compile can't know if someone casted an illegal value to the enum type. Consider:
E c = static_cast<E>( 42 );
The cast will compile without a warning (or even an error) as you are explicitly telling the compiler "I know what I'm doing, don't check the value". In practice, this sadly happens more often than you think. :(
Also, all code needs to be valid, even if it is later removed as unreachable. A static_assert(false,...) will fire at compile-time, independent of what would happen at run-time.

Enums are not restricted to the values that you name. They are restricted to values that fit in the underlying type, which is an integral type large enough to hold all the values. For example:
enum flags {
first = 0x01,
second = 0x02,
third = 0x04,
fourth = 0x08
};
flags operator | (flags f0, flags f1) {
return flags((int)f0 | (int)f1);
}
flags f = first | second; // okay; f holds 0x03

Related

Correct way to convert an enum to value

I work on a project that has a lot of enums defined like this:
enum BundleSize
{
BUNDLE_SIZE_5 = 5,
BUNDLE_SIZE_10 = 10,
BUNDLE_SIZE_107 = 107,
};
I wrote a function to get the value from it like:
int convertBundleSizeEnumToVal(BundleSize b)
{
switch(b)
{
case BUNDLE_SIZE_5: return 5; break;
case BUNDLE_SIZE_10: return 10; break;
case BUNDLE_SIZE_107: return 107; break;
default: // handle appropriately and error out
}
}
I realize I don't really need a converter (method 1 and 2 both work below):
BundleSize b = getRandomBundleSize();
printf("The size is %d\n", convertBundleSizeEnumToVal(b)); // method 1
printf("The size is %d\n", b); // method 2
But I feel that method 1 is still the "correct" way to do this, because in the future something like this might come along:
enum BundleSize
{
BUNDLE_SIZE_5 = 5,
BUNDLE_SIZE_5_POINT_5 = 6,
BUNDLE_SIZE_10 = 10,
BUNDLE_SIZE_107 = 107,
};
Which now effectively breaks method 2 without an obvious runtime error, whereas method 1 will atleast catch the problem in the default switch case.
I'm curious about what people think is the right way to handle these conversions.
You can use the static_cast operator:
static_cast<int>(b)
IMO, this is "correct". You shouldn't be defining functions to convert every possible enum variant to an integer, especially with large enums.
Actually, you are using simple enum, so you can simply use your enum variable as a value.
For enum class (strict version of enum) you should use static_cast to convert your enum to value.
You can simplify your function to:
int convertBundleSizeEnumToVal(BundleSize b)
{
switch(b)
{
case BUNDLE_SIZE_5:
case BUNDLE_SIZE_10:
case BUNDLE_SIZE_107:
return b;
default: // handle appropriately and error out
}
}
Method 2, is broken because the underlying type of enum is not necessarily int, and so the format specifier %d may be wrong and behaviour of the program may be undefined.
You can cast the enum value to int first, and it will be correct as long as you don't use higher values than can be represented by int. You can use either static_cast or explicit cast. Or you can use an implicit conversion:
int value = getRandomBundleSize();
printf("The size is %d\n", b);
Regarding which you should use, well it depends on what you need. If you think that enum values added later should not be converted by convertBundleSizeEnumToVal but should result in an error, then method 1 is indeed superior.
If you wish all enum values to be converted, then the function is error prone, as you would have to remember to add a case each time a new value is added. In this case method 2 is superior.

char data to float/double

I have a memory location of 128 bytes. I try to fill the memory with data starting from 1...127.
I need to write a code which get two parameter like offset , data type. Based on the arguments I need to convert the data on the memory to the specific datatype mentioned.
say for example
unsigned char *pointer = (unsigned char *)malloc(sizeof(unsigned char) * 128);
printf("\n\n loading some default values...");
for (unsigned int i = 0; i < 128; i++) {
pointer[i] = i + 1;
}
convertTo(3,efloat);
convertTo(100,edword);
void convertTo(uint8_t offset, enum datatype){
switch(datatype)
{
case efloat:
//// conversion code here..
break;
case edword:
//// conversion code here..
break;
case eint:
//// conversion code here..
break;
}
}
I tried using many methods like atoi, atof, strtod, strtol, etc.., but nothing gives me correct value. Say if I give offset as 2, eint(16-bit) which should take value 2,3 and give 515
Here is a generic version of what you want which wraps the type to convert to and the offset into a single struct. While the template code is more complicated, the usage is IMHO, much cleaner. Additionally, the long switch statement has been removed (at the expense of some less readable template code).
// Use an alias for the type to convert to (for demonstration purposes)
using NewType = short;
// Struct which wraps both the offset and the type after conversion "neatly"
template <typename ConversionType>
struct Converter {
// Define a constructor so that the instances of
// the converter can be created easily (see main)
Converter(size_t offset) : Offset(offset) {}
// This provides access to the type to convert to
using Type = ConversionType;
size_t Offset;
};
// Note: The use of the typename keyword here is to let the compiler know that
// ConverterHelper::Type is a type
template <typename ConverterHelper>
typename ConverterHelper::Type convertTo(char* Array, ConverterHelper ConvHelper) {
// This converts the bytes in the array to the new type
typename ConverterHelper::Type* ConvertedVar =
reinterpret_cast<typename ConverterHelper::Type*>(Array + ConvHelper.Offset);
// Return the value of the reinterpreted bytes
return *ConvertedVar;
}
int main()
{
char ExampleArray[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
// Create a new NewType (short) using bytes 1 and 2 in ExampleArray
NewType x = convertTo(ExampleArray, Converter<NewType>(1));
}
On the machine I used to test this, x had a value of 770, as John suggested it might.
If you remove the alias NewType and use the actual type you wish to convert to, the intention of convertTo is, again IMHO, very clear.
Here is a live demo Coliru Demo. Just change the type alias NewType to see the output for different types.
Try *reinterpret_cast<uint16_t*>(pointer + offset). Of course, what you will get depends on the endianess of your system. 0x02 0x03 might be interpreted as 0x0203 (515) or 0x0302 (770).

How to use C++11 enum class for flags

Say I have such a class:
enum class Flags : char
{
FLAG_1 = 1;
FLAG_2 = 2;
FLAG_3 = 4;
FLAG_4 = 8;
};
Now can I have a variable that has type flags and assign a value 7 for example? Can I do this:
Flags f = Flags::FLAG_1 | Flags::FLAG_2 | Flags::FLAG_3;
or
Flags f = 7;
This question arises because in the enum I have not defined value for 7.
You need to write your own overloaded operator| (and presumably operator& etc.).
Flags operator|(Flags lhs, Flags rhs)
{
return static_cast<Flags>(static_cast<char>(lhs) | static_cast<char>(rhs));
}
Conversion of an integer to an enumeration type (scoped or not) is well-defined as long as the value is within the range of enumeration values (and UB otherwise; [expr.static.cast]/p10). For enums with fixed underlying types (this includes all scoped enums; [dcl.enum]/p5), the range of enumeration values is the same as the range of values of the underlying type ([dcl.enum]/p8). The rules are trickier if the underlying type is not fixed - so don't do it :)
It's maybe better to make use of std::underlying_type instead of hard-coding char type.
Flags operator|(Flags lhs, Flags rhs) {
return static_cast<Flags>(
static_cast<std::underlying_type<Flags>::type>(lhs) |
static_cast<std::underlying_type<Flags>::type>(rhs)
);
}
Now, you can change the underlying type of your enumeration without needing to update that type in every bitwise operator overload.
It should handle any enumeration type. I'm not sure it doesn't have any side effects and is completely valid C++ code. Let me know if there are some issues.
template<class T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
constexpr T operator|(T lhs, T rhs)
{
return static_cast<T>(
static_cast<std::underlying_type<T>::type>(lhs) |
static_cast<std::underlying_type<T>::type>(rhs));
}
Please don't do this. If you need to do this, enum classs probably aren't what you need.
#T.C. showed you how to do it so long as you specify underlying type, but you will run into places where your program does things it just shouldn't.
An example is where you use a switch and have a case for every defined enum value.
e.g.
enum class my_enum: unsigned int{
first = 1,
second = 2,
third = 4,
fourth = 8
};
int main(){
auto e = static_cast<my_enum>(static_cast<unsigned int>(my_enum::first) | static_cast<unsigned int>(my_enum::second));
switch(e){
case my_enum::first:
case my_enum::second:
case my_enum::third:
case my_enum::fourth:
return 0;
}
std::cout << "Oh, no! You reached a part of the program you weren't meant to!\n";
return 1;
}
Will output:
Oh, no! You reached a part of the program you weren't meant to!
then return the error code 1.
Which is also an example of why you should always have a default case, of course, but that isn't my point.
Of course, you could argue that so long as the user of the enum class never directly uses the value other than passing to a function; it would be a good way of restricting the values of a bitset. But I've always been a little too trustworthy and find std::uint[n]_t and some constexpr variables the best way (if a user sets an invalid bit it simply does nothing).
What you're doing just isn't really suitable for enum class, because it defeats the purpose of having a scoped enumeration. You can no longer enumerate the values if you set it to an undefined one.
I realize this question is a bit old, but I will write out a method I have used to do this.
(If anything, if I Google this again in the future I have it documented to find again.)
Personally I like this method because intellisense (at least the VSCode version of it... I don't have Visual Studio on Linux...) will automatically pick up on what you're doing and give you useful hints. Also, it avoids the use of macros, so the compiler can warn you if it is not happy. Lastly, without the comments, it isn't a lot of code. You're not making a class and setting a bunch of overloads or anything, but you're still getting the benefit of scoped enums so that you can reuse a flag name/value for another enum. Anyway onto the example.
namespace FlagsNS
{
/* This is an old/classic style enum so put it in a
namespace so that the names don't clash
(ie: you can define another enum with the values of
Flag_1 or Flag_2, etc... without it blowing up)
*/
enum Flags
{
Flag_1 = 1 << 0, //Same as 1
Flag_2 = 1 << 1, //Same as 2
Flag_3 = 1 << 2, //Same as 4
Flag_4 = 1 << 3 //Same as 8
};
}
/* This is telling the compiler you want a new "type" called Flags
but it is actually FlagsNS::Flags. This is sort of like using the
#define macro, except it doesn't use the preprocessor so the
compiler can give you warnings and errors.
*/
using Flags = FlagsNS::Flags;
//Later in code.... so int main() for example
int main()
{
//If you don't mind c-style casting
Flags flag = (Flags)(Flags::FLAG_1 | Flags::FLAG_2 | Flags::FLAG_3);
//Or if you want to use c++ style casting
Flags flag = static_cast<Flags>(Flags::FLAG_1 | Flags::FLAG_2 | Flags::FLAG_3);
//Check to see if flag has the FLAG_1 flag set.
if (flag & Flags::FLAG_1)
{
//This code works
}
}
The code in question doesn't compile. But you can do something like this,
enum class Flags : char
{
FLAG_1 = 1,
FLAG_2 = 2,
FLAG_3 = 4,
FLAG_4 = 8,
};
int main() {
Flags f = static_cast<Flags>(7);
Flags f1 = static_cast<Flags>( static_cast<char>(Flags::FLAG_1) | static_cast<char>(Flags::FLAG_2) | static_cast<char>(Flags::FLAG_3) );
return 0;
}
and it works
At this point, It probably makes sense to define your own class to handle this.
/** Warning: Untested code **/
struct Flag {
static Flag Flag_1;
static Flag Flag_2;
static Flag Flag_3;
static Flag Flag_4;
Flag operator = (Flag);
private:
char const value;
};
Flag operator | (Flag, Flag);

How to automatically convert strongly typed enum into int?

#include <iostream>
struct a {
enum LOCAL_A { A1, A2 };
};
enum class b { B1, B2 };
int foo(int input) { return input; }
int main(void) {
std::cout << foo(a::A1) << std::endl;
std::cout << foo(static_cast<int>(b::B2)) << std::endl;
}
The a::LOCAL_A is what the strongly typed enum is trying to achieve, but there is a small difference : normal enums can be converted into integer type, while strongly typed enums can not do it without a cast.
So, is there a way to convert a strongly typed enum value into an integer type without a cast? If yes, how?
As others have said, you can't have an implicit conversion, and that's by-design.
If you want you can avoid the need to specify the underlying type in the cast.
template <typename E>
constexpr typename std::underlying_type<E>::type to_underlying(E e) noexcept {
return static_cast<typename std::underlying_type<E>::type>(e);
}
std::cout << foo(to_underlying(b::B2)) << std::endl;
Strongly typed enums aiming to solve multiple problems and not only scoping problem as you mentioned in your question:
Provide type safety, thus eliminating implicit conversion to integer by integral promotion.
Specify underlying types.
Provide strong scoping.
Thus, it is impossible to implicitly convert a strongly typed enum to integers, or even its underlying type - that's the idea. So you have to use static_cast to make conversion explicit.
If your only problem is scoping and you really want to have implicit promotion to integers, then you better off using not strongly typed enum with the scope of the structure it is declared in.
A C++14 version of the answer provided by R. Martinho Fernandes would be:
#include <type_traits>
template <typename E>
constexpr auto to_underlying(E e) noexcept
{
return static_cast<std::underlying_type_t<E>>(e);
}
As with the previous answer, this will work with any kind of enum and underlying type. I have added the noexcept keyword as it will never throw an exception.
Update
This also appears in Effective Modern C++ by Scott Meyers. See item 10 (it is detailed in the final pages of the item within my copy of the book).
A C++23 version would be to use the std::to_underlying function:
#include <utility>
std::cout << std::to_underlying(b::B2) << std::endl;
...or if the underlying type could be a 1 byte type:
std::cout << +(std::to_underlying(b::B2)) << std::endl;
The reason for the absence of implicit conversion (by design) was given in other answers.
I personally use unary operator+ for the conversion from enum classes to their underlying type:
template <typename T>
constexpr auto operator+(T e) noexcept
-> std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>>
{
return static_cast<std::underlying_type_t<T>>(e);
}
Which gives quite little "typing overhead":
std::cout << foo(+b::B2) << std::endl;
Where I actually use a macro to create enums and the operator functions in one shot.
#define UNSIGNED_ENUM_CLASS(name, ...) enum class name : unsigned { __VA_ARGS__ };\
inline constexpr unsigned operator+ (name const val) { return static_cast<unsigned>(val); }
Short answer is you can't as above posts point out. But for my case, I simply didn't want to clutter the namespace but still have implicit conversions, so I just did:
#include <iostream>
using namespace std;
namespace Foo {
enum Foo { bar, baz };
}
int main() {
cout << Foo::bar << endl; // 0
cout << Foo::baz << endl; // 1
return 0;
}
The namespacing sort of adds a layer of type-safety while I don't have to static cast any enum values to the underlying type.
No. There is no natural way.
In fact, one of the motivations behind having strongly typed enum class in C++11 is to prevent their silent conversion to int.
#include <cstdlib>
#include <cstdio>
#include <cstdint>
#include <type_traits>
namespace utils
{
namespace details
{
template< typename E >
using enable_enum_t = typename std::enable_if< std::is_enum<E>::value,
typename std::underlying_type<E>::type
>::type;
} // namespace details
template< typename E >
constexpr inline details::enable_enum_t<E> underlying_value( E e )noexcept
{
return static_cast< typename std::underlying_type<E>::type >( e );
}
template< typename E , typename T>
constexpr inline typename std::enable_if< std::is_enum<E>::value &&
std::is_integral<T>::value, E
>::type
to_enum( T value ) noexcept
{
return static_cast<E>( value );
}
} // namespace utils
int main()
{
enum class E{ a = 1, b = 3, c = 5 };
constexpr auto a = utils::underlying_value(E::a);
constexpr E b = utils::to_enum<E>(5);
constexpr auto bv = utils::underlying_value(b);
printf("a = %d, b = %d", a,bv);
return 0;
}
Hope this helps you or someone else
enum class EnumClass : int //set size for enum
{
Zero, One, Two, Three, Four
};
union Union //This will allow us to convert
{
EnumClass ec;
int i;
};
int main()
{
using namespace std;
//convert from strongly typed enum to int
Union un2;
un2.ec = EnumClass::Three;
cout << "un2.i = " << un2.i << endl;
//convert from int to strongly typed enum
Union un;
un.i = 0;
if(un.ec == EnumClass::Zero) cout << "True" << endl;
return 0;
}
This seems impossible with the native enum class, but probably you can mock a enum class with a class:
In this case,
enum class b
{
B1,
B2
};
would be equivalent to:
class b {
private:
int underlying;
public:
static constexpr int B1 = 0;
static constexpr int B2 = 1;
b(int v) : underlying(v) {}
operator int() {
return underlying;
}
};
This is mostly equivalent to the original enum class. You can directly return b::B1 for in a function with return type b. You can do switch case with it, etc.
And in the spirit of this example you can use templates (possibly together with other things) to generalize and mock any possible object defined by the enum class syntax.
As many said, there is no way to automatically convert without adding overheads and too much complexity, but you can reduce your typing a bit and make it look better by using lambdas if some cast will be used a bit much in a scenario. That would add a bit of function overhead call, but will make code more readable compared to long static_cast strings as can be seen below. This may not be useful project wide, but only class wide.
#include <bitset>
#include <vector>
enum class Flags { ......, Total };
std::bitset<static_cast<unsigned int>(Total)> MaskVar;
std::vector<Flags> NewFlags;
-----------
auto scui = [](Flags a){return static_cast<unsigned int>(a); };
for (auto const& it : NewFlags)
{
switch (it)
{
case Flags::Horizontal:
MaskVar.set(scui(Flags::Horizontal));
MaskVar.reset(scui(Flags::Vertical)); break;
case Flags::Vertical:
MaskVar.set(scui(Flags::Vertical));
MaskVar.reset(scui(Flags::Horizontal)); break;
case Flags::LongText:
MaskVar.set(scui(Flags::LongText));
MaskVar.reset(scui(Flags::ShorTText)); break;
case Flags::ShorTText:
MaskVar.set(scui(Flags::ShorTText));
MaskVar.reset(scui(Flags::LongText)); break;
case Flags::ShowHeading:
MaskVar.set(scui(Flags::ShowHeading));
MaskVar.reset(scui(Flags::NoShowHeading)); break;
case Flags::NoShowHeading:
MaskVar.set(scui(Flags::NoShowHeading));
MaskVar.reset(scui(Flags::ShowHeading)); break;
default:
break;
}
}
The C++ committee took one step forward (scoping enums out of global namespace) and fifty steps back (no enum type decay to integer). Sadly, enum class is simply not usable if you need the value of the enum in any non-symbolic way.
The best solution is to not use it at all, and instead scope the enum yourself using a namespace or a struct. For this purpose, they are interchangable. You will need to type a little extra when refering to the enum type itself, but that will likely not be often.
struct TextureUploadFormat {
enum Type : uint32 {
r,
rg,
rgb,
rgba,
__count
};
};
// must use ::Type, which is the extra typing with this method; beats all the static_cast<>()
uint32 getFormatStride(TextureUploadFormat::Type format){
const uint32 formatStride[TextureUploadFormat::__count] = {
1,
2,
3,
4
};
return formatStride[format]; // decays without complaint
}
Summary
Question:
is there a way to convert a strongly typed enum value into an integer type without a cast? If yes, how?
Answer:
No, there is not. Strongly typed enums can NOT be converted to integers without an explicit cast. Weak enums can, however, as they will be automatically implicitly cast. So, if you'd like automatic implicit conversion to an int, consider using a C-style weak enum instead (see more on this in the "Going further" section below).
From here (emphasis added): https://en.cppreference.com/w/cpp/language/enum --> under the section "Scoped enumerations":
There are no implicit conversions from the values of a scoped enumerator [AKA: "strong enum"] to integral types, although static_cast may be used to obtain the numeric value of the enumerator.
Going further: discussion of weak (C-style) vs strong (C++ enum class) enum types in C++
In C++ there are two types of enums:
"unscoped", "regular", "weak", "weakly typed", or "C-style" enums, and
"scoped", "strong", "strongly typed", "enum class", or "C++-style" enums.
"Scoped" enums, or "strong" enums, give two additional "features" beyond what "regular" enums give you.
Scoped enums:
don't allow implicit casting from the enum type to an integer type (so you can't do what you want to do implicitly!), and
they "scope" the enum so that you have to access the enum through its enum type name.
1. Example of an enum class (available only in C++):
// enum class (AKA: "strong" or "scoped" enum)
enum class my_enum
{
A = 0,
B,
C,
};
my_enum e = my_enum::A; // scoped through `my_enum::`
e = my_enum::B;
// NOT ALLOWED!:
// error: cannot convert ‘my_enum’ to ‘int’ in initialization
// int i = e;
// But explicit casting works just fine!:
int i1 = static_cast<int>(e); // explicit C++-style cast
int i2 = (int)e; // explicit C-style cast
The first "feature" may actually be something you don't want, in which case you just need to use a regular C-style enum instead! And the nice thing is: you can still "scope" or "namespace" the enum, as has been done in C for decades, by simply prepending its name with the enum type name, like this:
2. Example of a regular enum (available in both C and C++):
// regular enum (AKA: "weak" or "C-style" enum)
enum my_enum
{
// C-style-scoped through the `MY_ENUM_` prefix
MY_ENUM_A = 0,
MY_ENUM_B,
MY_ENUM_C,
};
my_enum e = MY_ENUM_A; // scoped through `MY_ENUM_`
e = MY_ENUM_B;
// This works fine!
int i = e;
Notice you still get the benefit of "scoping" simply by adding the MY_ENUM_ "scope" to the front of each enum!
3. Both regular enums and enum classes together:
Test the code here: https://onlinegdb.com/BkWGqlqz_.
main.cpp:
#include <iostream>
#include <stdio.h>
// enum class (AKA: "strong" or "scoped" enum [available only in C++, not C])
enum class my_enum
{
A = 0,
B,
C,
};
// regular enum (AKA: "weak" or "C-style" enum [available in BOTH C and C++])
enum my_enum2
{
MY_ENUM_A = 0,
MY_ENUM_B,
MY_ENUM_C,
};
int main()
{
printf("Hello World\n");
// 1) scoped enum
my_enum e = my_enum::A; // scoped through `my_enum::`
e = my_enum::B;
// IMPLICIT CASTING TO INT IS NOT ALLOWED!
// int i = e; // "error: cannot convert ‘my_enum’ to ‘int’ in initialization"
// But this explicit C++-style cast works fine:
int i1 = static_cast<int>(e);
// This explicit C-style cast works fine too, and is easier to read
int i2 = (int)e;
// 2) regular enum
my_enum2 e2 = MY_ENUM_A; // scoped through `MY_ENUM_`
e2 = MY_ENUM_B;
// This implicit cast works fine / IS allowed on C-style enums!
int i3 = e2;
// These explicit casts are also fine, but explicit casting is NOT
// required for regular enums.
int i4 = static_cast<int>(e2); // explicit C++-style cast
int i5 = (int)e2; // explicit C-style cast
return 0;
}
4. How to iterate over enums:
*****[my answer] Full examples of how to iterate over both 1. weakly-typed C-style and 2. scoped, strongly-typed C++ enum class enums: How can I iterate over an enum?
[my Q&A] What are commonly-used ways to iterate over an enum class in C++?
An extension to the answers from R. Martinho Fernandes and Class Skeleton: Their answers show how to use typename std::underlying_type<EnumType>::type or std::underlying_type_t<EnumType> to convert your enumeration value with a static_cast to a value of the underlying type. Compared to a static_cast to some specific integer type, like, static_cast<int> this has the benefit of being maintenance friendly, because when the underlying type changes, the code using std::underlying_type_t will automatically use the new type.
This, however, is sometimes not what you want: Assume you wanted to print out enumeration values directly, for example to std::cout, like in the following example:
enum class EnumType : int { Green, Blue, Yellow };
std::cout << static_cast<std::underlying_type_t<EnumType>>(EnumType::Green);
If you later change the underlying type to a character type, like, uint8_t, then the value of EnumType::Green will not be printed as a number, but as a character, which is most probably not what you want. Thus, you sometimes would rather convert the enumeration value into something like "underlying type, but with integer promotion where necessary".
It would be possible to apply the unary operator+ to the result of the cast to force integer promotion if necessary. However, you can also use std::common_type_t (also from header file <type_traits>) to do the following:
enum class EnumType : int { Green, Blue, Yellow };
std::cout << static_cast<std::common_type_t<int, std::underlying_type_t<EnumType>>>(EnumType::Green);
Preferrably you would wrap this expression in some helper template function:
template <class E>
constexpr std::common_type_t<int, std::underlying_type_t<E>>
enumToInteger(E e) {
return static_cast<std::common_type_t<int, std::underlying_type_t<E>>>(e);
}
Which would then be more friendly to the eyes, be maintenance friendly with respect to changes to the underlying type, and without need for tricks with operator+:
std::cout << enumToInteger(EnumType::Green);

Why can't I increment a variable of an enumerated type?

I have a enumerated type StackID, and I am using the enumeration to refer to an index of a particular vector and it makes my code easier to read.
However, I now have the need to create a variable called nextAvail of type StackID. (it actually refers to a particular stackID ). I tried to increment it but in C++, the following is illegal:
nextAvail++;
Which sort of makes sense to me ... because there's no bounds checking.
I'm probably overlooking something obvious, but what's a good substitute?
I also want to link to this question.
I'm probably overlooking something obvious, but what's a good substitute?
Overloading operator++:
// Beware, brain-compiled code ahead!
StackID& operator++(StackID& stackID)
{
#if MY_ENUMS_ARE_CONTIGUOUS && I_DO_NOT_WORRY_ABOUT_OVERFLOW
return stackID = static_cast<StackID>( ++static_cast<int>(stackID) );
#else
switch(stackID) {
case value1 : return stackID = value2;
case value2 : return stackID = value3;
...
case valueN : return stackID = value1;
}
assert(false);
return stackID; // some compilers might warn otherwise
#endif
}
StackID operator++(StackID& stackID, int)
{
StackID tmp(stackID);
++stackID;
return tmp;
}
Because enumerations do not have to be contiguous. E.g. take this example:
enum Colors {
cRed, // = 0
cBlue, // = 1
cGreen = 3
}
What should happen in this scenario?
Colors color = cBlue;
Colors other = color++;
Should other be cGreen or should it be 2. In that case it's not a valid enumeration member anymore. What about this?
Colors color = cGreen;
Colors other = color++;
Should other be cRed (wrap around) or 4?
As you can see, being able to increment enumeration values introduces a whole lot of questions and complicates the simple mechanism that they intend to be.
If all you care about is the integer value being incremented, then simply cast to int and increment that.
Casting back and forth to/from int is of course the obvious solution, then you make clear that you understand that the addition is happening "outside" the enum:
nextAvail = static_cast<StackID>(static_cast<int>(nextAvail) + 1);
Why not store nextAvail as an int instead if you're going to do arithmetic operations on it?
Another option would be to wrap the enum in your own type and overload operator ++ for it (which also could wrap around or something for instance).
An enumeration is semantically supposed to represent a set of distinct related, values.
So you could have
enum Colour {RED, GREEN, BLUE};
But that should be equivalent to:
enum Colour {GREEN, BLUE, RED};
The problem is that if you increment an enum then those representations are not the same. GREEN++ in the first case is not the same as GREEN++ in the second.
Making your program dependent on the declaration of the enum is a recipe for disaster - maintainers may assume that the order of the enum doesnt matter, introducing many silent bugs.
Very Simple:
nextAvail = (StackID)(nextAvail + 1);
Enums are going to be type int, so you can cast them. Is this what you're trying to do?
int ndx = (int) StackID.SomeValue;
...
++ndx;
This is going to make someone very confused down the line, of course.
It occurs to me that you're using an enum where you should be using const, or even #define. enum is most appropriate when you have arbitrary values (where the exact value is not meaningful).
I've overloaded the ++/-- operator in this way:
enum STATE {STATE_1, STATE_2, STATE_3, STATE_4, STATE_5, STATE_6};
// Overload the STATE++ operator
inline STATE& operator++(STATE& state, int) {
const int i = static_cast<int>(state)+1;
state = static_cast<STATE>((i) % 6);
return state;
}
// Overload the STATE-- operator
inline STATE& operator--(STATE& type, int) {
const int i = static_cast<int>(type)-1;
if (i < 0) {
type = static_cast<STATE>(6);
} else {
type = static_cast<STATE>((i) % 6);
}
return type;
}
With respect to oprator++, $5.2.6/1 states- "The type of the operand shall be an arithmetic type or a pointer to a complete object type."
StackID does not fit the bill here. It is of enumeration type.
One option is like this
$5.7/1 - "For addition, either both operands shall have arithmetic or enumeration type, or one operand shall be a pointer to a completely defined object type and the other shall have integral or enumeration type."
enum Possibility {Yes, No, Maybe};
Possibility operator++(Possibility const& r){
return Possibility(r + 1); // convert r to integer, add 1, convert back to Enum
}
int main(){
Possibility p = Yes;
Possibility p1 = ++p;
}
I'm quite happy with this C plus C++ solution for a for loop incrementing an enum.
for (Dwg_Version_Type v = R_INVALID; v <= R_AFTER; v++)
=>
int vi;
for (Dwg_Version_Type v = R_INVALID;
v <= R_AFTER;
vi = (int)v, vi++, v = (Dwg_Version_Type)vi)
The other solutions here are not C backcompat, and quite large.