ChatGPT解决这个技术问题 Extra ChatGPT

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?

i know, i want o know why its giving me the error!
Its Wednesday here. You have too lot of syntax errors for C++ compiler. Starting from 'Enum'.
@Hossein, Because enums aren't the same syntax (and semantics) in both languages. The first thing I do after getting an error when trying to use a feature in a new language is look up the syntax (or if it's possible) in that language.
@chris:I know , i do the same exact thing.hopefully i got my answer.I also updated the question to be more clearer.Thank you by the way;)
"as far as i know the enums declaration and usage in these two languages are the same.". There's your problem, right there. C# is not the same language as C++. Particularly, they have different syntax for enums.

1
1MinLeft

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!


Fortunately, your complaint 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!
Gotta love the C++ error messages...they prove that the language is to cumbersome to even give good feedback. I take it a 'primary-expression' is an object or a scope or some other thing that is NOT a type. Perhaps a Type is a 'secondary-expression'. And what a C++ developer might call a 'dot operator' the C++ compiler can only call a 'token'. When it gets that hard to understand the error messages there is something wrong with the language I think.
@Travis: en.cppreference.com/w/cpp/language/…. A primary expression is just the first thing in an expression, usually a name or variable or a literal. As for the second part, I don't see a big difference between '.' token and dot operator, other than it's a token and not an operator, and it shows the exact symbol, rather than a name.
@Mike Seymour I've tried to access the enums without the scope resolution operators on a bunch of compilers, and it seems to work. You said as of C++11 it's the only way, for some reason I can just access the enum values as globals, don't need the ::
@TitoneMaurice: If you have an enum, you can use no scope, or the global scope (::Saturday). If you have an enum class (which is a very different thing), then you have to use Days::Saturday.
1
1MinLeft

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";
}

why is it wrong to say if ( day== Days.Satudday) ? they must be the same,so why is compiler complaining about it?
@Hossein the values declared in your enum do not behave like class or struct member variables. This is not the correct syntax to use
@Hossein: because Days is not a scope, nor object. It is a type. And Types themselves don't have members. std::string.clear also fails to compile for the same reason.
@Hossein: Because that's not how enums in C++ work. Unscoped enumerations put their values into the surrounding namespace; scoped ones (enum class, new in 2011) have their own scope, and are accessed using the scope operator, Days::Saturday. The member access operator (.) is only used to access class members.
@MooingDUck and MikeSeymour Would one of you guys post your answer as an answer? because that is exactly what i was after by issuing this question ;)
p
pb2q

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;

I have updated the question,I think its now clearer what i'm exactly after:) By the way thankyou:)
a
ataman1x

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)

D
Dean Knight

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

The nice thing here is that compilers will tell you if you missed putting a case in.
Shouldnt you use class enum in this case?
enum is just a datatype in C++ So declaring an enum like I did above in a .h file, and then including that file in whatever .cpp file you want to use it in will give you access to the enum. Just noticed I forgot to add the #include in my .cpp example. Editing.
Also, I see someone else saying that enums in C++ are global. In my experience, using enums the way I have above, I can only access them when I have included the .h. So this seems to stop global access too, which is always good. EDIT: It seems like I am unknowingly using enums in a C++11 way if I am reading things right...
P
Peter Mortensen

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!


S
San

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";
}

b
bames53

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;

G
Grzegorz

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.


Until you use enum class in C++11, that is. Before that, you have to make dummy classes.
Don't know C++11. I am assuming the question refers to C++. Yes, using classes or namespaces will do the trick.
@Grzegorz: i think chris is referring to the newly introduced enum class which provides strongly typed enums.
@Hossein: Thank you for pointing it out. I have found explanation of the num class, and I know what Chris was talking about. Thanks a lot.
@Grzegorz:I didn't mean to disrespect,just thought i might be helping,sorry for any probable misunderstanding.I again Thank you for your time and helping me ;)
I
InitializeSahib

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

P
Peter Mortensen

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){}


The OP changed the spelling/case 16 minutes after the initial post (revision 1 to revision 2).
J
James Oravec

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";
}

This does not work: to use the Days:: scope as in your example, you must define the enumeration with enum class Days and use C++03+Microsoft extension or C++11.
@Futal, the above ran with Borland C++ Builder. Flavor / Version of C++ is not in the question.
your version of Borland C++ Builder must be using C++11 or newer. Gcc and Clang both gives errors or warnings if your example is compiled with -std=c++98 or -std=c++03. Clang is quite clear: warning: use of enumeration in a nested name specifier is a C++11 extension.
X
Xu Hui

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


C
CommanderLake

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


P
Peter Mortensen

First of all, make 'E' in enum, 'e' as a lower case.

Second, drop type name 'Days' in 'Days.Saturday'.

Third ...buy yourself a good C++ book.


Sorry you got all these down-votes (I mean, the answer does kind of deserve it), but that doesn't mean you have to leave the community for 6 years. Come back and join us. You have something to contribute too. Be helpful. Share knowledge.