我一直在尝试阅读一些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;
}
答案 0 :(得分:16)
枚举类是一个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.
至于序列化部分(我认为它不是原始问题的一部分),我更喜欢创建一个帮助类,它将枚举项转换为它们的字符串等效(和返回),因为名称通常比它们表示的整数值,因为枚举项可以(有时是)重新排序而不改变代码行为。
答案 1 :(得分: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
这个序列化问题不是特别有意义(因为序列化数据的大小不是恒定宽度,这可能会在枚举及其基础类型发生变化时引起问题),但通常很有趣。存储整个枚举的类型。干杯!
答案 2 :(得分:5)
我没有读过任何C ++ 0x的东西,所以我无法对此发表评论。
至于序列化,在重新读取枚举时不需要切换 - 只需将其转换为枚举类型。
但是,在写入流时我没有强制转换。这是因为我经常喜欢写一个运算符&lt;&lt;对于enum所以我可以捕获写入的错误值,或者我可以决定写出一个字符串。
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
答案 3 :(得分: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;
答案 4 :(得分:1)
关于enum class color
:这是C ++ / CLI(C ++ .NET)还是未来的C ++ 0x代码?
对于序列化,您可以使用sizeof(color)
获取枚举的大小,以了解要复制的字节数。