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
,如果枚举在声明时未进行强类型键入,则会破坏编译过程。
答案 0 :(得分:1)
std::underlying_type
可用于将编译限制为一组fixed width integer types
(例如std::is_same
):
#include <type_traits>
#include <cstdint>
template <typename T>
constexpr bool is_fixed =
std::is_same<T, std::int8_t>::value ||
std::is_same<T, std::int16_t>::value
// etc..
;
enum class E1 : std::int8_t {};
static_assert( is_fixed<std::underlying_type_t<E1>>, "fixed");
enum class E2 {};
static_assert(!is_fixed<std::underlying_type_t<E2>>, "not fixed");
变量模板确实是C ++ 14以来的版本,但是在C ++ 11中,可以使用constexpr
函数或struct
/ class
实现相同的模板:
template <typename T>
constexpr bool is_fixed_f() {
return std::is_same<T, std::int8_t>::value ||
std::is_same<T, std::int16_t>::value
// etc..
;
}
template <typename T>
struct is_fixed_s {
static constexpr bool value =
std::is_same<T, std::int8_t>::value ||
std::is_same<T, std::int16_t>::value
// etc..
;
};
答案 1 :(得分:0)
回答标题问题:不,不可能知道枚举是否具有显式的基础类型。
即使有,它也不能解决您的实际问题,更像是“如何知道枚举类型的大小是否固定?”
想象一个简单的例子:
enum class Foo : long {};
在某些系统上,这将是32位,而在其他系统上,它将是64位。因此,即使某种机制让您发现它具有显式类型,它也无济于事,因为它的大小不可移植。