如何在C ++中使用枚举


218

假设我们有一个enum类似下面的内容:

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};

我想为此创建一个实例enum并使用适当的值对其进行初始化,所以我这样做:

Days day = Days.Saturday;

现在,我要检查具有现有enum值的变量或实例,所以我这样做:

if (day == Days.Saturday)
{
    std::cout << "Ok its Saturday";
}

这给了我一个编译错误:

错误:“。”之前的预期主表达式 代币

所以要明确一点,说之间有什么区别?

if (day == Days.Saturday) // Causes compilation error

if (day == Saturday)

这两个实际上指的是什么,一个可以确定,一个会导致编译错误?


4
我知道,我想知道为什么它会给我错误!
里卡2012年

1
它的星期三在这里。对于C ++编译器,您有太多语法错误。从“枚举”开始。
OO Tiib

1
@Hossein,因为在两种语言中枚举的语法(和语义)都不相同。在尝试使用一种新语言使用功能时遇到错误后,我要做的第一件事就是查找该语言的语法(如果可能)。
克里斯

@chris:我知道,我做同样的事情。希望我能得到答案。我也更新了这个问题,使问题更加清楚。谢谢您;)
Rika

17
据我所知,这两种语言的枚举声明和用法是相同的。 ” 那里是你的问题。C#是相同的语言C ++。特别是,它们对于枚举具有不同的语法。
罗伯(Robᵩ)2012年

Answers:


350

这段代码是错误的:

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Days.Saturday;
if (day == Days.Saturday)

因为Days不是范围,也不是对象。这是一种。类型本身没有成员。您写的内容等同于std::string.clearstd::string是一种类型,因此无法.在其上使用。您.在类的实例上使用。

不幸的是,枚举是不可思议的,因此类比就此停止。因为可以使用类std::string::clear来获取指向成员函数的指针,但是在C ++ 03 Days::Sunday中无效。(这是可悲的)。这是因为C ++在某种程度上可以与C向后兼容,并且C没有名称空间,因此枚举必须在全局名称空间中。所以语法很简单:

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Saturday;
if (day == Saturday)

幸运的是,Mike Seymour观察到这已在C ++ 11中解决。变化enumenum class它并拥有自己的范围;因此Days::Sunday,不仅有效,而且是访问的唯一方法Sunday。快乐的时光!


254
幸运的是,您的投诉已在C ++ 11中得到解决。变化enumenum class它并拥有自己的范围;因此Days::Sunday,不仅有效,而且是访问的唯一方法Sunday。快乐的时光!
迈克·西摩

10
一定喜欢C ++错误消息...它们证明该语言很麻烦,甚至无法给出良好的反馈。我认为“主表达式”是对象或作用域或其他不是类型的东西。类型可能是“第二表达式”。C ++开发人员可能将其称为“点运算符”,而C ++编译器只能称为“令牌”。当难以理解错误消息时,我认为该语言有问题。
特拉维斯

4
@Travis:en.cppreference.com/w/cpp/language/…。主表达式只是表达式中的第一件事,通常是名称,变量或文字。至于第二部分,我看不到'.' token和之间的大区别dot operator,只是它是一个令牌而不是一个运算符,它显示的是确切的符号,而不是名称。
Mooing Duck 2016年

@Mike Seymour我试过在一系列编译器上不使用范围解析运算符的情况下访问枚举,并且似乎可以正常工作。您说从C ++ 11开始,这是唯一的方法,由于某些原因,我可以将枚举值作为全局变量来访问,不需要
Zebrafish

1
@TitoneMaurice:如果有enum,则不能使用任何作用域或全局作用域(::Saturday)。如果您有enum class(这是非常不同的事情),则必须使用Days::Saturday
Mooing Duck

24

这足以声明您的枚举变量并进行比较:

enum Days {Saturday, Sunday, Tuesday, Wednesday, Thursday, Friday};
Days day = Saturday;
if (day == Saturday) {
    std::cout << "Ok its Saturday";
}

为什么说if(day == Days.Satudday)是错误的?它们必须相同,那么为什么编译器会抱怨呢?
里卡2012年

1
@Hossein枚举中声明的值的行为不同于类或结构成员变量。这不是使用的正确语法
mathematician1975

2
@侯赛因:因为Days不是作用域,也不是对象。这是一种。类型本身没有成员。 std::string.clear出于同样的原因也无法编译。
Mooing Duck 2012年

7
@侯赛因:因为那不是C ++中枚举的工作方式。无作用域的枚举将其值放入周围的名称空间中。作用域的对象(enum class,2011年新增)具有自己的作用域,并且可以使用作用域运算符进行访问Days::Saturday。成员访问运算符(.)仅用于访问类成员。
Mike Seymour

@MooingDUck和MikeSeymour你们中的一个可以将您的答案发布为答案吗?因为这正是我通过发出此问题之后的目的;)
里卡(Rika

22

其中大部分应该会给您带来编译错误。

// note the lower case enum keyword
enum Days { Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday };

现在,SaturdaySunday等可以被用作顶级裸常量和Days可以用作一个类型:

Days day = Saturday;   // Days.Saturday is an error

然后类似地,进行测试:

if (day == Saturday)
    // ...

这些enum值是像裸常量-它们是联合国 -scoped -从编译器一点额外的帮助:(除非你使用C ++ 11 枚举类),他们封装像物体或结构成员的实例,你不能把它们称为成员Days

您将拥有使用C ++ 11寻找的东西,它引入了enum class

enum class Days
{
    SUNDAY,
    MONDAY,
    // ... etc.
}

// ...

if (day == Days::SUNDAY)
    // ...

请注意,此C ++在几方面与C有所不同,一种是C enum在声明变量时要求使用关键字:

// day declaration in C:
enum Days day = Saturday;

我已经更新了问题,我想它现在更清楚了我的确切意思:)顺便谢谢:)
Rika

13

您可以使用技巧来随意使用范围,只需以这种方式声明枚举即可:

struct Days 
{
   enum type
   {
      Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday
   };
};

Days::type day = Days::Saturday;
if (day == Days::Saturday)

9

枚举不是使用一堆if语句,而是很好地使用它们来切换语句

我在为游戏创建的关卡生成器中使用了一些枚举/开关组合。

编辑:另一件事,我看到你想要类似的语法;

if(day == Days.Saturday)
etc

您可以在C ++中执行此操作:

if(day == Days::Saturday)
etc

这是一个非常简单的示例:

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

这里的好处是,编译器会告诉你,如果你错过了推杆的情况。
克里斯-

在这种情况下,您不应该使用类枚举吗?
里卡

1
枚举只是C ++中的一种数据类型,因此像我在.h文件中一样声明一个枚举,然后将该文件包含在要使用它的任何.cpp文件中,将使您可以访问该枚举。只是注意到我忘了在我的.cpp示例中添加#include。编辑中。
迪恩·奈特

另外,我看到有人说C ++中的枚举是全局的。根据我的经验,以上面的方式使用枚举,只有在包含.h后才能访问它们。因此,这似乎也阻止了全局访问,这总是很好。编辑:好像我在不知不觉中以C ++ 11的方式使用枚举,如果我没看错的话……
迪恩·奈特

8

如果您仍在使用C ++ 03并想使用枚举,则应在名称空间内使用枚举。例如:

namespace Daysofweek{
enum Days {Saturday, Sunday, Tuesday,Wednesday, Thursday, Friday};
}

您可以在名称空间之外使用枚举,例如,

Daysofweek::Days day = Daysofweek::Saturday;

if (day == Daysofweek::Saturday)
{
    std::cout<<"Ok its Saturday";
}

7

您正在寻找强类型枚举,这是C ++ 11标准中可用的功能。它将枚举转换为具有范围值的类。

使用您自己的代码示例,它是:

  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

使用::作为访问器来枚举如果靶向C ++标准的现有C ++ 11将失败。但是某些旧的编译器不支持它,有些IDE会覆盖此选项,并设置旧的C ++ std。

如果使用的是GCC,请使用-std = c ++ 11-std = gnu11启用C + 11 。

要开心!


1
你忘了写enum class Days { ...
马丁·亨宁斯

确实。修好它!谢谢。
亚历克斯·伯斯

6

这在C ++中不起作用:

Days.Saturday

Days不是包含可以通过点运算符访问的成员的范围或对象。此语法只是一种C#-ism,在C ++中是不合法的。

Microsoft长期以来一直在维护C ++扩展,该扩展允许您使用范围运算符访问标识符:

enum E { A, B, C };

A;
E::B; // works with Microsoft's extension

但这在C ++ 11之前是非标准的。在C ++ 03中,枚举中声明的标识符仅存在于与枚举类型本身相同的作用域中。

A;
E::B; // error in C++03

C ++ 11使用枚举名称限定枚举标识符合法,并且引入了枚举类,该类为标识符创建了新范围,而不是将它们放在周围的范围内。

A;
E::B; // legal in C++11

enum class F { A, B, C };

A; // error
F::B;

4

尽管C ++(不包括C ++ 11)具有枚举,但它们中的值被“泄漏”到全局名称空间中。
如果您不希望它们泄漏(并且不需要使用枚举类型),请考虑以下事项:

class EnumName {  
   public:   
      static int EnumVal1;  
      (more definitions)  
};  
EnumName::EnumVal1 = {value};  
if ([your value] == EnumName::EnumVal1)  ...

3

可悲的是,枚举的元素是“全局的”。您可以通过这样做访问它们day = Saturday。这意味着您不能拥有enum A { a, b } ;enum B { b, a } ;因为它们存在冲突。


2
直到您enum class在C ++ 11中使用它为止。在此之前,您必须创建虚拟类。
克里斯,2012年

不懂C ++ 11。我假设问题涉及C ++。是的,使用类或名称空间可以解决问题。
Grzegorz

@Grzegorz:我认为克里斯指的是新引入的枚举类,它提供了强类型的枚举。
里卡2012年

@侯赛因:谢谢你指出。我已经找到了有关num类的解释,而且我知道Chris在说什么。非常感谢。
Grzegorz

@Grzegorz:我不是无视我的意思,只是想我可能会在帮忙,对不起您的任何误会。我再次感谢您的时间和帮助;)
Rika

3

C ++中的枚举就像是在声明枚举值时被其名称掩盖的整数(这不仅是定义,仅提示其工作方式)。

但是您的代码中有两个错误:

  1. 拼写enum所有小写
  2. 您不需要Days.在星期六之前。
  3. 如果此枚举在类中声明,则使用 if (day == YourClass::Saturday){}

OP在最初发布(修订版1修订版2)后16分钟更改了拼写/大小写。
彼得·莫滕森

1

我认为您的根本问题是使用.而不是::,它将使用命名空间。

尝试:

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

这是行不通的:要Days::像您的示例中那样使用作用域,必须使用定义枚举enum class Days并使用C ++ 03 + Microsoft扩展或C ++ 11。
致命的

@Futal,以上与Borland C ++ Builder一起运行。Flavor / C ++版本不是问题。
James Oravec

1
您的Borland C ++ Builder版本必须使用C ++ 11或更高版本。如果您的示例使用-std=c++98或编译,则Gcc和Clang均会给出错误或警告-std=c++03。lang很清楚:warning: use of enumeration in a nested name specifier is a C++11 extension
致命的

1

如果我们需要严格的类型安全性和作用域枚举,enum class则在C ++ 11中使用很好。

如果我们在C ++ 98不得不工作,我们可以使用给出的建议InitializeSahibSan以使范围的枚举。

如果我们还需要严格的类型安全性,那么以下代码可以实现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;
}

该代码是从有效的C ++ 3rd:Item 18中的Month类示例修改而来的


-15

首先,将枚举中的“ E”设为小写。

其次,在“ Days.Saturday”中删除类型名称“ Days”。

第三...给自己买一本不错的C ++书。


5
对不起,您得到了所有这些反对票(我的意思是,答案的确值得),但这并不意味着您必须离开社区6年。回来加入我们。您也有贡献。有所帮助。分享知识。
加布里埃尔·斯台普斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.