27

我一直在尝试阅读一些 C++ 标准,以了解枚举的工作原理。实际上比我最初想象的要多。

int对于范围枚举,除非使用 enum-base 子句另行指定(它可以是任何整数类型),否则基础类型很明显。

enum class color { red, green, blue};  // these are int

对于无范围的枚举,似乎基础类型可以是任何可以工作的整数类型,并且它不会大于 int,除非它需要。

enum color { red, green, blue};  // underlying type may vary

由于无范围枚举的底层类型没有标准化,那么处理序列化枚举实例的最佳方法是什么?到目前为止,我一直int在写入时转换为,然后在读取时序列化为一个int并在开关中设置我的enum变量,但这似乎有点笨拙。有没有更好的办法?

enum color { red, green, blue };
color c = red;
// to serialize
archive << (int)c;
// to deserialize
int i;
archive >> i;
switch(i) {
  case 0: c = red; break;
  case 1: c = green; break;
  case 2: c = blue; break;
}
4

5 回答 5

16

enum 类C++0x的一个特性,它在 C++03 中不存在。

在标准 C++ 中,枚举不是类型安全的。它们实际上是整数,即使枚举类型不同。这允许在不同枚举类型的两个枚举值之间进行比较。C++03 提供的唯一安全性是整数或一种枚举类型的值不会隐式转换为另一种枚举类型。此外,不能明确指定底层整数类型,即整数的大小;它是实现定义的。最后,枚举值的范围是封闭范围。因此,两个单独的枚举不可能具有匹配的成员名称。C++0x 将允许对没有这些问题的枚举进行特殊分类。这是使用枚举类声明表示的

示例(来自维基百科文章):

enum Enum1;                   //Illegal in C++ and C++0x; no size is explicitly specified.
enum Enum2 : unsigned int;    //Legal in C++0x.
enum class Enum3;             //Legal in C++0x, because enum class declarations have a default type of "int".
enum class Enum4: unsigned int; //Legal C++0x.
enum Enum2 : unsigned short;  //Illegal in C++0x, because Enum2 was previously declared with a different type.

至于序列化部分(我认为这不是原始问题的一部分),我更喜欢创建一个帮助类,将枚举项转换为等效的字符串(并返回),因为名称通常比它们的整数值更稳定表示,因为枚举项可以(有时是)重新排序而不改变代码行为。

于 2009-05-12T15:32:27.433 回答
14

我决定创建一个新答案,因为我的旧答案太乱了。不管怎样,我只想说一些关于 C++11 的事情,你可以在其中使用这个获得枚举的底层类型:

std::underlying_type_t<E>

并且为了兴趣,重载解决的想法。但请按照@lothar 的建议使用名称来存储枚举。

重载决议源于这样一个事实:从枚举到 int、unsigned int、long、unsigned long 中的第一个可以表示其基础类型的所有值。转换为任何其他整数类型的排名较低,重载决议不喜欢它。

char (& f(int) )[1];
char (& f(unsigned int) )[2];

char (& f(long) )[3];
char (& f(unsigned long) )[4];

char const* names[] = { 
    "int", "unsigned int", 
    "long", "unsigned long"
};

enum a { A = INT_MIN };
enum b { B = UINT_MAX };
enum c { C = LONG_MIN };
enum d { D = ULONG_MAX };

template<typename T> void print_underlying() {
    std::cout << names[sizeof(f(T()))-1] << std::endl;
}

int main() { 
    print_underlying<a>();
    print_underlying<b>();
    print_underlying<c>();
    print_underlying<d>();
}

它在这里打印这个:

int
unsigned int
int
unsigned int

这个序列化问题并不是特别感兴趣(因为序列化的数据的大小不是恒定宽度,当枚举及其底层类型发生变化时,这可能会导致问题),但找出存储类型通常很有趣整个枚举。干杯!

于 2009-05-12T17:04:01.497 回答
5

我还没有读过任何 C++0x 的东西,所以我无法对此发表评论。

至于序列化,在读回枚举时不需要开关 - 只需将其转换为枚举类型即可。

但是,我在写入流时不会强制转换。这是因为我经常喜欢为枚举写一个 operator<<,这样我就可以捕捉到正在写入的错误值,或者我可以决定写出一个字符串来代替。

enum color { red, green, blue };
color c = red;

// to serialize
archive << c;    // Removed cast

// to deserialize
int i;
archive >> i;
c = (color)i;    // Removed switch
于 2009-05-12T16:23:24.700 回答
5
#include <type_traits>

enum a { bla1, bla2 };
typedef typename std::underlying_type<a>::type underlying_type;

if (std::is_same<underlying_type, int>::value)
  std::cout << "It's an int!" << endl;
else if (std::is_same<underlying_type, unsigned int>::value)
  std::cout << "It's an uint!" << endl;
于 2012-07-11T19:02:40.380 回答
1

至于enum class color:这是 C++/CLI (C++ .NET) 还是未来的 C++0x 代码?

对于序列化,您可以获取枚举的大小sizeof(color)以了解要复制多少字节。

于 2009-05-12T15:47:36.787 回答