【问题标题】:Enum and anonymous enum in C++C++ 中的枚举和匿名枚举
【发布时间】:2013-07-24 10:52:53
【问题描述】:

1) 下面的代码显示了 enum 元素星期三的索引。我怎样才能让它打印值而不是索引。

int main()
{
    enum day{sunday,monday,tuesday,wednesday,thursday,friday,saturday};
    day d=wednesday;
    cout<<d;
    return 0;
}

2)在什么情况下我会更喜欢匿名枚举而不是枚举

【问题讨论】:

  • 这段代码打印枚举的值。
  • 我假设他的意思是打印“星期三”。
  • 但是我应该像cout&lt;&lt;day[d](这是错误的)那样进行哪些更改来打印迭代值。
  • 枚举不是容器。
  • 枚举只是在代码中修饰数字的一种奇特方式。它们的存在是为了使您的代码更具可读性,但归根结底,它们只是整数。

标签: c++


【解决方案1】:

1)。您的代码打印枚举的值,而不是索引。在您的具体示例中,索引与值相同(默认情况下,枚举的第一个值获取数值 0,其余获取连续递增值。

检查:

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

如果“打印值”是指打印“星期三”,您应该这样做:

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

编辑:

2) 在什么情况下我会更喜欢匿名枚举而不是枚举

当您不需要将匿名枚举作为参数传递但需要为常量数值分配有意义的名称时,您更喜欢匿名枚举:

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

在这里使用匿名枚举很好,因为在将值作为参数传递的地方,你需要一个 int,而不是枚举类型。如果你需要一个枚举类型,那么你必须给它一个名字。否则,你不会。

【讨论】:

  • 所以如果我必须进行比较,那么我应该像if(d==8) 那样做而不是if(d==wednesday)
  • 对于枚举,你永远不应该明确地使用它们的整数值。基本上,您应该始终使用if(d == wednesday)。这将允许您更改枚举值,而无需通过代码并将其更改为匹配(day d=wednesday; if(d == wednesday) 将始终评估为真,无论枚举中的周三值如何)。
  • 感谢您的努力。它对我帮助很大。您能帮我完成第二部分吗。
【解决方案2】:

首先,该语言不提供任何映射 字符串的内部枚举值。它不能,真的;考虑:

enum Numbers {
    one = 1,
    two = 2,
    three = 3,
    un = 1,
    deux = 2,
    trois = 3
};

将枚举常量分配给枚举变量后,它 包含数值,仅此而已。如果 上面的数值是2,系统怎么知道 是否应该映射到twodeux

在实践中,映射在许多情况下都很有用。沿着 前段时间,我写了一个简单的解析器来生成映射代码; 它忽略了大部分 C++,在某些情况下不起作用,例如这 枚举被包装在一个宏中,它生成的代码不会 如果枚举是私有的或受保护的,并且它是未定义的,则编译 在上述情况下你会得到哪个字符串,但我仍然 发现它非常有用。

对于第二个问题:匿名枚举通常用于 枚举的唯一目的是生成常量。事物 喜欢:

enum { maxSize = 4096 };

在您提供初始化之前被广泛使用 静态成员变量的常量。我经常发现它 方便使用匿名枚举定义位掩码,甚至 当实际值是某种无符号类型时。 比如:

enum {
    offsetMask = 0xF000,
    offsetShift = 12,
    NS = 0x100,
    CWR = 0x80,
    ECE = 0x40,
    URG = 0x20,
    ACK = 0x10,
    //  ...
};
uint16_t flags;
//  ...
flags = offset << offsetShift | ACK;

我不想将我的变量声明为具有枚举;他们一定 正好是 16 位(根据 TCP 规范)。在 C 中, 我可能会使用 #define,在现代 C++ 中,我可能会 使用static uint16_t const成员变量,但通过out 我的 C++ 职业生涯的大部分时间,都像上面那样 正常的解决方案。

【讨论】:

    【解决方案3】:

    您必须手动维护枚举值的字符串“描述”数组,这既繁琐又容易出错:

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

    【讨论】:

      【解决方案4】:

      枚举是一个数字,字符串表示(例如星期三)是编译时表示。

      你需要这样的东西:

      const char *dayname[] = {"sunday","monday","tuesday","wednesday","thursday","friday","saturday"};
      
      ...
      cout << dayname[(unsigned)d];
      ...
      

      【讨论】:

      • 只是为了记录,你不需要演员表。
      【解决方案5】:

      试试下面的代码:

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

      【讨论】:

      • 谢谢,我把枚举当作数组。
      【解决方案6】:

      1)如果只想要整数值,可以写一个operator &lt;&lt;重载:

      template<typename _stream>
      _stream& operator << (const day& value) {
        _stream << static_cast<int>(value);
        return _stream;
      }
      

      另外,考虑使用 enum class 而不是普通的 enum(当然,如果允许使用 C++11)。

      2) 我会说可能有 1 种这样的情况:命名空间常量,假设您有一个 Person 类并希望有一些类内常量,例如 MaxAgeMaxNameLength。但即使在这种情况下,将限制包装在 enum class Settings 之类的东西中通常也是值得的。

      【讨论】:

        【解决方案7】:

        此主题的类型安全变体是使用 enum class 并将其用作 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;
        }
        

        这意味着使用整数类型访问映射会导致编译时错误。

        【讨论】:

        • 另一方面,您不想手动编写此代码,并且代码生成器很容易将其包装在类型安全函数中。它甚至可以在静态对象的构造函数中工作。
        猜你喜欢
        • 1970-01-01
        • 2010-11-26
        • 2011-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多