'How to use enums in C++
Suppose we have an enum
like the following:
enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
I want to create an instance of this enum
and initialize it with a proper value, so I do:
Days day = Days.Saturday;
Now I want to check my variable or instance with an existing enum
value, so I do:
if (day == Days.Saturday)
{
std::cout << "Ok its Saturday";
}
Which gives me a compilation error:
error: expected primary-expression before ‘.’ token
So to be clear, what is the difference between saying:
if (day == Days.Saturday) // Causes compilation error
and
if (day == Saturday)
?
What do these two actually refer to, in that one is OK and one causes a compilation error?
Solution 1:[1]
This code is wrong:
enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Days.Saturday;
if (day == Days.Saturday)
Because Days
is not a scope, nor object. It is a type. And Types themselves don't have members. What you wrote is the equivalent to std::string.clear
. std::string
is a type, so you can't use .
on it. You use .
on an instance of a class.
Unfortunately, enums are magical and so the analogy stops there. Because with a class, you can do std::string::clear
to get a pointer to the member function, but in C++03, Days::Sunday
is invalid. (Which is sad). This is because C++ is (somewhat) backwards compatable with C, and C had no namespaces, so enumerations had to be in the global namespace. So the syntax is simply:
enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Saturday;
if (day == Saturday)
Fortunately, Mike Seymour observes that this has been addressed in C++11. Change enum
to enum class
and it gets its own scope; so Days::Sunday
is not only valid, but is the only way to access Sunday
. Happy days!
Solution 2:[2]
This will be sufficient to declare your enum variable and compare it:
enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Saturday;
if (day == Saturday) {
std::cout << "Ok its Saturday";
}
Solution 3:[3]
Much of this should give you compilation errors.
// note the lower case enum keyword
enum Days { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday };
Now, Saturday
, Sunday
, etc. can be used as top-level bare constants,and Days
can be used as a type:
Days day = Saturday; // Days.Saturday is an error
And similarly later, to test:
if (day == Saturday)
// ...
These enum
values are like bare constants - they're un-scoped - with a little extra help from the compiler: (unless you're using C++11 enum classes) they aren't encapsulated like object or structure members for instance, and you can't refer to them as members of Days
.
You'll have what you're looking for with C++11, which introduces an enum class
:
enum class Days
{
SUNDAY,
MONDAY,
// ... etc.
}
// ...
if (day == Days::SUNDAY)
// ...
Note that this C++ is a little different from C in a couple of ways, one is that C requires the use of the enum
keyword when declaring a variable:
// day declaration in C:
enum Days day = Saturday;
Solution 4:[4]
You can use a trick to use scopes as you wish, just declare enum in such way:
struct Days
{
enum type
{
Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday
};
};
Days::type day = Days::Saturday;
if (day == Days::Saturday)
Solution 5:[5]
Rather than using a bunch of if-statements, enums lend themselves well to switch statements
I use some enum/switch combinations in the level builder I am building for my game.
EDIT: Another thing, I see you want syntax similar to;
if(day == Days.Saturday)
etc
You can do this in C++:
if(day == Days::Saturday)
etc
Here is a very simple example:
EnumAppState.h
#ifndef ENUMAPPSTATE_H
#define ENUMAPPSTATE_H
enum eAppState
{
STARTUP,
EDIT,
ZONECREATION,
SHUTDOWN,
NOCHANGE
};
#endif
Somefile.cpp
#include "EnumAppState.h"
eAppState state = eAppState::STARTUP;
switch(state)
{
case STARTUP:
//Do stuff
break;
case EDIT:
//Do stuff
break;
case ZONECREATION:
//Do stuff
break;
case SHUTDOWN:
//Do stuff
break;
case NOCHANGE:
//Do stuff
break;
}
Solution 6:[6]
You are looking for strongly typed enumerations, a feature available in the C++11 standard. It turns enumerations into classes with scope values.
Using your own code example, it is:
enum class Days {Saturday, Sunday, Tuesday,Wednesday, Thursday, Friday};
Days day = Days::Saturday;
if (day == Days::Saturday) {
cout << " Today is Saturday !" << endl;
}
//int day2 = Days::Sunday; // Error! invalid
Using ::
as accessors to enumerations will fail if targeting a C++ standard prior C++11. But some old compilers doesn't supported it, as well some IDEs just override this option, and set a old C++ std.
If you are using GCC, enable C+11 with -std=c++11 or -std=gnu11 .
Be happy!
Solution 7:[7]
If you are still using C++03 and want to use enums, you should be using enums inside a namespace. Eg:
namespace Daysofweek{
enum Days {Saturday, Sunday, Tuesday,Wednesday, Thursday, Friday};
}
You can use the enum outside the namespace like,
Daysofweek::Days day = Daysofweek::Saturday;
if (day == Daysofweek::Saturday)
{
std::cout<<"Ok its Saturday";
}
Solution 8:[8]
This should not work in C++:
Days.Saturday
Days is not a scope or object that contains members you can access with the dot operator. This syntax is just a C#-ism and is not legal in C++.
Microsoft has long maintained a C++ extension that allows you to access the identifiers using the scope operator:
enum E { A, B, C };
A;
E::B; // works with Microsoft's extension
But this is non-standard before C++11. In C++03 the identifiers declared in an enum exist only in the same scope as the enum type itself.
A;
E::B; // error in C++03
C++11 makes it legal to qualify enum identifiers with the enum name, and also introduces enum classes, which create a new scope for the identifiers instead of placing them in the surrounding scope.
A;
E::B; // legal in C++11
enum class F { A, B, C };
A; // error
F::B;
Solution 9:[9]
Sadly, elements of the enum are 'global'. You access them by doing day = Saturday
. That means that you cannot have enum A { a, b } ;
and enum B { b, a } ;
for they are in conflict.
Solution 10:[10]
While C++ (excluding C++11) has enums, the values in them are "leaked" into the global namespace.
If you don't want to have them leaked (and don't NEED to use the enum type), consider the following:
class EnumName {
public:
static int EnumVal1;
(more definitions)
};
EnumName::EnumVal1 = {value};
if ([your value] == EnumName::EnumVal1) ...
Solution 11:[11]
Enums in C++ are like integers masked by the names you give them, when you declare your enum-values (this is not a definition only a hint how it works).
But there are two errors in your code:
- Spell
enum
all lower case - You don't need the
Days.
before Saturday. - If this enum is declared in a class, then use
if (day == YourClass::Saturday){}
Solution 12:[12]
I think your root issue is the use of .
instead of ::
, which will use the namespace.
Try:
enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Days::Saturday;
if(Days::Saturday == day) // I like literals before variables :)
{
std::cout<<"Ok its Saturday";
}
Solution 13:[13]
If we want the strict type safety and scoped enum, using enum class
is good in C++11.
If we had to work in C++98, we can using the advice given by InitializeSahib
,San
to enable the scoped enum.
If we also want the strict type safety, the follow code can implement somthing like enum
.
#include <iostream>
class Color
{
public:
static Color RED()
{
return Color(0);
}
static Color BLUE()
{
return Color(1);
}
bool operator==(const Color &rhs) const
{
return this->value == rhs.value;
}
bool operator!=(const Color &rhs) const
{
return !(*this == rhs);
}
private:
explicit Color(int value_) : value(value_) {}
int value;
};
int main()
{
Color color = Color::RED();
if (color == Color::RED())
{
std::cout << "red" << std::endl;
}
return 0;
}
The code is modified from the class Month example in book Effective C++ 3rd: Item 18
Solution 14:[14]
Don't think of an enum as a group of objects, think of it as an integer where each numeric value has a name so enum Days
would be better declared as enum Day
.
If you want to contain it within a named structure put enum Day
within a struct Days
like this:
struct Days{
enum Day{
Saturday,
Sunday,
Tuesday,
Wednesday,
Thursday,
Friday
};
};
Then you would address them like this Days::Saturday
and the type would be Days::Day
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow