C++ - Get "id" of class's variable from enum class [duplicate] - c++

This question already has an answer here:
c++ enum class integer not working for array subscript
(1 answer)
Closed 2 years ago.
If I have code:
class A {
public:
int x;
enum class nums {
Ab = 0,
Bc,
Cd,
De,
Ef
};
A() { this->x = 0; }
}Avar [5];
Is somehow possible to use enum nums numbers as "id" for class's variable Avar[], so I don't need to converting to int with static_cast<> or int()?
if (Avar[static_cast<int>(A::nums::Cd)].x == 10) {
Something like Avar[A::nums::Cd].x ?

An enum class (aka scoped enumeration) is not implicitly convertible to an integer and cannot thus be used as an index of an array without a cast. You can use a plain enum instead of an enum class. Unlike enum classes, an enum is implicitly convertible to an integer and can therefore be used as an index of an array.
P.S. Don't use a magic number for the size of the array. Use an extra enum value that will have the size:
enum nums {
Ab = 0,
Bc,
Cd,
De,
Ef,
nums_count,
};
...
}Avar [A::nums_count];

Related

Colon : used in variable initialization? [duplicate]

This question already has answers here:
What does a colon in a struct declaration mean, such as :1, :7, :16, or :32?
(3 answers)
Closed 7 years ago.
I found this line here:
uint32 bIsHungry : 1;
... and I've never seen this syntax used to initialize a variable.
I'm used to seeing this:
uint32 bIsHungry = 1;
It looks kind of like an initialization list, but for a single field?
What is it, what does it do, why should I care?
That line is a bit field declaration and it declares a data member with an explicit bit-level size
Example from cppreference:
#include <iostream>
struct S {
// three-bit unsigned field,
// allowed values are 0...7
unsigned int b : 3;
};
int main()
{
S s = {7};
++s.b; // unsigned overflow
std::cout << s.b << '\n'; // output: 0
}
Notice that in the example above the unsigned overflow is defined behavior (same doesn't apply if b were declared as a signed type)
The documentation you links also states that
Boolean types can be represented either with the C++ bool keyword or as a bitfield
Regarding why should I care I recommend reading this other question
It is not initialization, it is a fragment of a declaration.
struct {
// ...
uint32 bIsHungry : 1;
// ...
};
declares a bIsHungry as a bitfield member of the struct. It says that bIsHungry is an unsigned int whose length is 1 bit. Its possible values are 0 and 1.
Read more about bitfields: http://en.cppreference.com/w/c/language/bit_field
This is bitfield declaration, Declares a class data member with explicit size, in bits.

Why I can't assign the correct value to c++ enum type variable?

I can't understand what's going there.
Using Visual Studio 2008, I've defined an enum like this:
enum MyType{
A,
B,
C
};
Then I use it to initialize a member variable:
class MyClass
{
private:
bool bit_;
uint16 num_;
MyType member_;
public:
MyClass(MyType value){
member_ = value; // This the assignment which fails
} // Here, there's a breakpoint to query member_ value
};
MyClass instance = new MyClass();
I'm using Debug configuration, so no optimization can fool me when reading
a variable. At a breakpoint just after the assignment, the debuger shows the value of member_ as member_ = C.
It could be a debugger whatch refresh issue but, inside a method it evaluates true when checking:
if(member_ == C){
// ??
}
And also, assigning to the other values gives strange numbers, e.g. doing member_ = B gives member_ = 258 when ferching it.
Can you tell me what's wrong? Thanks in advance.
EDIT #1
I've noted a funny effect which explains why after assigning member_ = A the expression member_ == C evaluates to true for the enum with the default values:
For the enum
enum MyType{ A, B, C}; // equivalent to enum MyType{ A = 0, B = 1, C = 2};
I get
MyType a = A; // but when fetching a the value is 2 (0x0002) thats the map for C!
MyType b = B; // but when fetching a the value is 258 (0x0102)
MyType c = C; // but when fetching a the value is 514 (0x0202)
But if I make
enum MyType{ A = 5, B = 6, C = 7};
I get
MyType a = A; // but when fetching a the value is 1282 (0x0502)
MyType b = B; // but when fetching a the value is 1538 (0x0602)
MyType c = C; // but when fetching a the value is 1794 (0x0702)
So, when assigning that #?!^% enum, the rule seems to be, shift 8 bits and add 2.
It sounds like compiler issues.
Btw, making the type of member_ to be int instead MyType doesn't changes nothing.
EDIT #2
Added two more members to the class, which are the real cause of the problem. I'll post the
answer as soon as the time restriction vanishes (8h from the posting of the question).
Enum entries does not have to have unique values. You might have an enum with A,B,C where both A and C are equal to '42'. In such case, when the var has value of 42, the IDE will show you only one of the matching entries, A or C, not both.
You can easily create an enum with 'duplicate' entries, like this:
enum { A=1, B=1, C=1 }
But most probably, you didn't do it like that. However, when using autonumbering, you can accidentally (or intentionally) create duplicates too:
enum { A, B, C } // 0,1,2
enum { A, B, C=0 } // 0,1,0
enum { A=2, B=1, C } // 2,1,2
enum { A=-1, B, C=0 } // -1,0,0
Be sure to double-check your enum definition.
see i.e. http://www.learncpp.com/cpp-tutorial/45-enumerated-types/
Thanks everyone.
Somebody at work pointed me to the origin of the problem.
It's a matter of faulty configuration of the project,
which gives data alignment issues.
After compiling, with the current project settings,
the two first members of the class are 3 bytes of size.
It should be 4 bytes, hence the misalignment of 1 byte.
The extra 2 added is garbage at the misaligned byte, so, the
whole effect is to shift one byte and add 2.
This effect is cancealed adding an extra member, although
it's not an elegant solution (the solution is to configure
the project corectly).
class MyClass
{
private:
bool bit_; // 1 byte
uint16 num_; // 2 byte
bool dummy; // extra byte to help the alignment
MyType member_;
public:
MyClass(MyType value){
member_ = value; // Now it works as expected.
}
};

Enum and anonymous enum in C++

1) The following code shows the index of the enum element wednesday .How can i make it to print the value instead of the index.
int main()
{
enum day{sunday,monday,tuesday,wednesday,thursday,friday,saturday};
day d=wednesday;
cout<<d;
return 0;
}
2) In what situation will I prefer anonymous enum over enum
1). Your code prints the value of the enum, not the index. In your specific example, the index is the same as the value (by default, the first value of an enum gets the numerical value 0, and the rest get consecutive increasing values.
To check:
int main()
{
enum day{sunday = 5,monday,tuesday,wednesday,thursday,friday,saturday};
day d=wednesday;
cout<<d; // will print 8 (as in 5 + 1 + 1 + 1)
return 0;
}
If by "print the value" you meant printing "wednesday", you should do this:
enum day{sunday,monday,tuesday,wednesday,thursday,friday,saturday};
std::ostream& operator << (std::ostream& out, const day d)
{
static const char *as_strings[] = {"sunday", "monday",
"tuesday", "wednesday", "thursday", "friday", "saturday"
};
return out << as_strings[static_cast<int>(d)]; // this only works
// for enum values starting from 0 and being consecutive
// otherwise you should use a switch(d) and
// print each value separately
}
int main()
{
day d=wednesday;
cout<<d; // will print wednesday
return 0;
}
Edit:
2) In what situation will I prefer anonymous enum over enum
You prefer an anonymous enum when you do not need to pass it as a parameter, but need to assign meaningful names to constant numeric values:
my_object record_to_myobject(record& r)
{
enum {id, value1, value2}; // indexes within record
int result_id = r[id]; // much more meaningful than r[0]
int result_value1 = r[value1];
int result_value2 = r[value2];
return my_object{result_id, result_value1, result_value2};
}
It's fine to use an anonymous enum here because where you pass the value as argument, you need an int, not an enum type. If you need an enum type, then you have to give it a name. Otherwise, you do not.
First, the language doesn't provide any means of mapping the
internal enum value to a string. It can't, really; consider:
enum Numbers {
one = 1,
two = 2,
three = 3,
un = 1,
deux = 2,
trois = 3
};
Once you've assigned the enum constant to an enum variable, it
contains the numerical value, and nothing else. And if the
numerical value in the above is 2, how can the system know
whether it should map to two or to deux.
In practice, the mapping is useful in many contexts. A long
time ago, I wrote a simple parser to generate the mapping code;
it ignores most of C++, won't work in cases where e.g. the
enum is wrapped in a macro, the code it generates won't
compile if the enum is private or protected, and it's undefined
which string you get in cases like the above, but I've still
found it extremely useful.
For the second question: anonymous enums are usually used when
the only purpose of the enum is to generate constants. Things
like:
enum { maxSize = 4096 };
were widely used before you could provide the initialization
constant for static member variables. And I've often found it
convenient to define bit masks using an anonymous enum, even
when the actual values were on some sort of unsigned type.
Things like:
enum {
offsetMask = 0xF000,
offsetShift = 12,
NS = 0x100,
CWR = 0x80,
ECE = 0x40,
URG = 0x20,
ACK = 0x10,
// ...
};
uint16_t flags;
// ...
flags = offset << offsetShift | ACK;
I don't want to declare my variables to have an enum; they must
be exactly 16 bits (according to the TCP specification). In C,
I'd probably have used a #define, and in modern C++, I might
use static uint16_t const member variables, but through out
most of my C++ career, something like the above would have been
the normal solution.
You have to manually maintain an array of string "descriptions" of the enum values, which is tedious and error-prone:
static const char *daydescs[] = {
"sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"
};
int main()
{
enum day{sunday,monday,tuesday,wednesday,thursday,friday,saturday};
day d=wednesday;
cout<< daydescs[(unsigned)d];
return 0;
}
An enum is a number, the string representation (e.g. wednesday) is a compile time representation.
You would need something like:
const char *dayname[] = {"sunday","monday","tuesday","wednesday","thursday","friday","saturday"};
...
cout << dayname[(unsigned)d];
...
Try code below :
int main()
{
enum day{sunday,monday,tuesday,wednesday,thursday,friday,saturday};
String days[7] = {"sunday","monday","tuesday","wednesday","thursday","friday","saturday"};
day d=wednesday;
cout<<days[d];
return 0;
}
1) If you only want the integer value, you can write an operator << overload:
template<typename _stream>
_stream& operator << (const day& value) {
_stream << static_cast<int>(value);
return _stream;
}
Also, consider using enum class instead of a plain enum (if you are allowed to use C++11, of course).
2) I would say there could be 1 such case: namespace constants, say you have a Person class and want to have some in-class constants like MaxAge or MaxNameLength. But even in such cases, wrapping restrictions in something like enum class Settings is usually worth it.
A type-safe variation on this theme would be to use enum class and use it as a key in std::map
#include <string>
#include <map>
#include <iostream>
int main()
{
enum class day
{
sunday,
monday,
tuesday,
wednesday,
thursday,
friday,
saturday
};
std::map<day,std::string> days =
{
std::make_pair(day::sunday, "Sunday"),
std::make_pair(day::monday, "Monday"),
std::make_pair(day::tuesday, "Tuesday"),
std::make_pair(day::wednesday, "Wednesday"),
std::make_pair(day::thursday, "Thursday"),
std::make_pair(day::friday, "Friday"),
std::make_pair(day::saturday, "Saturday")
};
std::cout << days[day::sunday] << std::endl;
}
This means that accessing the map with an integral type will cause a compile-time error.

Advantage of array of enum over constant and macro? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Should I use #define, enum or const?
Advantage and disadvantages of #defines vs. constants?
How enum will be more useful than #define and const.
memory and code visibilty point of view and readability point of view.
can I convert (type cast) enum to array of int, If I have taken all value within integer.
Example:
class MapPlt_clContainer {
public:
enum tagVectorType {
enVTAll = 0,
enVTPolygon,
enVTLines
}
};
tVoid MapPlt_clRender::vDrawLineClass( MapPlt_clContainer::tagVectorType* )
While calling function enum pass
vDrawLineClass( ClassArray_Group ); //Working
While calling array base address pass
int test[3] =
{
5,
6,
7,
};
vDrawLineClass( test); //Not Working
Error!!
Should it type cast it automatically? or it is compiler dependent. In my case it is giving error.
enum is a separate type unlike #define and the language (with the help of compiler) will help you ensure you are not mixing values of different types (even if they are of the same numerical value).
Additionally the value of an enum is available to the debugger whereas the original meaning of the #define is lost during the pre-processing time (before the code generation has even begun).
Type-casting an enum to an int is an automatic built-in process while the opposite conversion is trickier as not all the int values could be valid for your particular enum.
Modern compilers will also warn you if you have used all the possible enum's values in a switch statement that has no default clause, something that cannot be checked for #defines
If you are using an enum as an integer in C++ you have a smell. An enum defines a type, and only the values of that type should be used. (I realize this isn't enforced and the enum can be interpreted as an int, but with C++ it generally shouldn't).
Also, a big pet peeve of mine: Don't put "Type" in the name for an enum in C++. The values of an enum are not "types" (in the C++ sense of the word). As soon as you start doing template code, you will HATE all the enums with the word Type in their type name.
Also, any time you are trying to typecast in your design, you are doing it wrong. That is an awful smell in C++. You shouldn't have to do it, and you certainly shouldn't design it into your code (i.e. use it as a "feature").
Finally, this part:
int test[3] =
{
5,
6,
7,
};
vDrawLineClass( test); //Not Working
This is a straight up ugly hack. Do what you say, say what you do:
MapPlt_clContainer::tagVectorType test[3] =
{
MapPlt_clContainer::enVTAll,
MapPlt_clContainer::enVTPolygon,
MapPlt_clContainer::enVTLines
};
vDrawLineClass( test);
In addition to the points made in other answers, I would like to add the following:
If you have multiple types and you need to iterate on them, you will have to use an array of constants, which will be something like this:
const int states[] = {STATE_1,STATE_2, STATE_3, STATE_4 };
int numStates = sizeof(states)/sizeof(state[0]);
for (int i = 0; i < numStates; i++) {
// Do something with states[i]..
}
With enumerations, this can be simplified as
enum states{cState_1 = 0, cState_2, cState_3, cState_4, cNumStates};
for (int i = 0; i < numStates; i++) {
// do something with i
}

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);