【发布时间】:2019-01-24 20:49:05
【问题描述】:
C++11 为我们处理枚举的方式引入了两个不同的附加功能:一个使它们具有作用域的选项,以及一个使它们具有类型的选项。所以现在我们有四种不同的枚举子类型:
enum Old {};
enum Typed : int8_t {};
enum class Scoped {};
enum class TypedScoped : int8_t {};
This question 询问如何确定枚举是否有作用域。我想知道如何判断枚举是否有类型。
附加信息
我使用 Qt 框架,它提供了QDataStream 类,用于以可移植的跨平台方式对数据进行序列化/反序列化。
显然,为了使生成的数据流具有可移植性,您必须以固定长度形式存储所有整数。这也包括枚举。
过去,我制作了几个帮助宏来定义枚举的序列化/反序列化,方法是将它们转换为具有固定(用户指定)长度的整数:
#define SC_DECLARE_DATASTREAM_WRITE_OPERATOR(_TYPE) \
QDataStream &operator<<(QDataStream &stream, _TYPE v);
#define SC_DECLARE_DATASTREAM_READ_OPERATOR(_TYPE) \
QDataStream &operator>>(QDataStream &stream, _TYPE &v);
#define SC_DECLARE_DATASTREAM_OPERATORS(_TYPE) \
SC_DECLARE_DATASTREAM_WRITE_OPERATOR(_TYPE) \
SC_DECLARE_DATASTREAM_READ_OPERATOR(_TYPE)
#define SC_DEFINE_DATASTREAM_ENUM_WRITE_OPERATOR(_TYPE, _LEN) \
QDataStream &operator<<(QDataStream &stream, _TYPE v) \
{ \
qint ## _LEN t = v; \
static_assert(sizeof(t) >= sizeof(v), "Increase length"); \
stream << t; \
return stream; \
}
#define SC_DEFINE_DATASTREAM_ENUM_READ_OPERATOR(_TYPE, _LEN) \
QDataStream &operator>>(QDataStream &stream, _TYPE &v) \
{ \
qint ## _LEN t {0}; \
static_assert(sizeof(t) >= sizeof(v), "Increase length"); \
stream >> t; \
if(stream.status() == QDataStream::Ok) \
v = static_cast<_TYPE>(t); \
return stream; \
}
#define SC_DEFINE_DATASTREAM_ENUM_OPERATORS(_TYPE, _LEN) \
SC_DEFINE_DATASTREAM_ENUM_WRITE_OPERATOR(_TYPE, _LEN) \
SC_DEFINE_DATASTREAM_ENUM_READ_OPERATOR(_TYPE, _LEN)
既然 C++11 允许指定底层枚举类型,我可以简化上面提到的宏:
#define SC_DEFINE_DATASTREAM_TYPED_ENUM_WRITE_OPERATOR(_TYPE) \
QDataStream &operator<<(QDataStream &stream, _TYPE v) \
{ \
const std::underlying_type<_TYPE>::type t {static_cast<std::underlying_type<_TYPE>::type>(v)}; \
stream << t; \
return stream; \
}
#define SC_DEFINE_DATASTREAM_TYPED_ENUM_READ_OPERATOR(_TYPE) \
QDataStream &operator>>(QDataStream &stream, _TYPE &v) \
{ \
std::underlying_type<_TYPE>::type t {0}; \
stream >> t; \
if(stream.status() == QDataStream::Ok) \
v = static_cast<_TYPE>(t); \
return stream; \
}
但是,如果用户不小心将新的 (*_TYPED_*) 宏用于未指定其底层类型的枚举,则会破坏可移植性的保证,因为在不同平台上编译相同的代码可能会产生不同的底层类型因此序列化/反序列化代码中的整数长度不同。
我需要在代码中添加一个static_assert,如果枚举在声明时不是强类型,这将中断编译过程。
【问题讨论】:
-
你真正想做什么?无论如何,都有一些方法可以获取底层类型。
-
你认为
enum Old { VALUE = -1ULL; };是一个类型化的枚举吗? -
我不知道你是否可以检查
enum是否有指定类型,但你可以检查底层类型是什么:en.cppreference.com/w/cpp/types/underlying_type -
@VictorGubin 你从哪里得到的?
int默认情况下仅适用于未指定类型的挖掘枚举。 -
@VictorGubin 所以你刚才引用的与你之前所说的相反。 底层类型是实现定义的整数类型,可以表示所有枚举值;此类型不大于 int,除非枚举器的值不能适合 int 或 unsigned int 表示从
char到int的任何值都可以接受,具体取决于值。法律允许enum foo { bar };具有char的基础类型。
标签: c++ c++11 enums typetraits