C++中的枚举和匿名枚举

7

1)以下代码显示了枚举元素“星期三”的索引。我该如何使它打印出值而不是索引。

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

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


4
此代码会打印枚举的值。 - R. Martinho Fernandes
但是我应该做出什么更改,例如将cout<<day[d](这是错误的)更改为打印字面值呢? - Naveen
@SlxS:是的,我想要打印星期三 - Naveen
2
枚举只是一种将数字装扮成代码中的花哨方式。它们存在的目的是为了使您的代码更易读,但最终它们只是整数。 - dandan78
@InsaneCoder 我认为这个链接已经涵盖了你所需要的信息:https://dev59.com/CWw05IYBdhLWcg3wmC6_ - SlxS
显示剩余4条评论
7个回答

8

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

如果您指的是打印“wednesday”这个值,您应该这样做:

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) - Naveen
1
使用枚举时,您不应明确使用它们的整数值。基本上,您应始终使用 if(d == wednesday)。这将允许您更改枚举值,而无需通过代码并将其更改为匹配项(day d=wednesday; if(d == wednesday) 将始终评估为 true,无论枚举中 wednesday 的值如何)。 - utnapistim
谢谢你的努力。它对我很有帮助。你能帮忙做第二部分吗? - Naveen

3

首先,该语言并没有提供任何将内部枚举值映射到字符串的方法。实际上它不可能这么做;请考虑以下情况:

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

一旦你将枚举常量分配给枚举变量,它就包含了数字值,没有别的东西。如果上面的数字值是2,系统怎么知道它应该映射到two还是deux

实际上,在许多情况下,这种映射是有用的。很久以前,我写了一个简单的解析器来生成映射代码;它忽略了大部分C++,在某些情况下不适用,比如枚举被包裹在宏中、生成的代码如果枚举是私有或保护的则不能编译,而且在类似上面的情况下,你得到的字符串是未定义的,但我仍然发现它非常有用。

对于第二个问题:匿名枚举通常用于只生成常量的目的。像这样的事情:

enum { maxSize = 4096 };

在静态成员变量提供初始化常量之前,C++ 里广泛使用了 const 数组。即使实际值是某种无符号类型,我也经常发现使用匿名枚举定义位掩码很方便。比如:

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

我不想声明我的变量为枚举类型; 根据TCP规范,它们必须正好占用16位。在C语言中,我可能会使用#define,而在现代C ++中,我可能会使用static uint16_t const成员变量,但在我大部分的C ++职业生涯中,像上面这样的解决方案是常见的。


0

你必须手动维护一个字符串数组,其中包含枚举值的“描述”,这是繁琐且容易出错的:

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

0

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

你需要像这样的东西:

const char *dayname[] = {"sunday","monday","tuesday","wednesday","thursday","friday","saturday"};

...
cout << dayname[(unsigned)d];
...

2
只是为了记录,你不需要进行强制类型转换。 - James Kanze

0

尝试下面的代码:

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

谢谢,我将枚举作为数组处理了。 - Naveen

0

1) 如果你只想要整数值,你可以编写一个 operator << 重载:

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

此外,如果您可以使用C++11,考虑使用枚举类而不是普通的枚举

2)我认为可能有一种情况:命名空间常量,比如您有一个Person类,并想要在类中定义一些常量,例如MaxAgeMaxNameLength。但即使在这种情况下,将限制封装在类似于enum class Settings的东西中通常也是值得的。


0
一个类型安全的变体是使用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;
}

这意味着使用整数类型访问地图将导致编译时错误。


另一方面,您不想手写此代码,而您的代码生成器足够轻松地将其包装在类型安全的函数中。这可以使它甚至在静态对象的构造函数中工作。 - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接