(反)序列化枚举 class
(De)serializing an enum class
我正在尝试序列化和反序列化(使用 QDataStream
但这与这里无关)一个 enum class
变量:
enum class Type : char
{
Trivial,
Complex
};
连载很简单:
QDataStream &operator<<(QDataStream &stream, Type type)
{
return stream << static_cast<char>(type);
}
但是反序列化不是:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return stream >> static_cast<char &>(type);
}
显然,static_cast
of reference to enum class
to a reference to its underlying type 是不允许的。此外, "obvious" 解决方案:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return stream >> reinterpret_cast<char &>(type);
}
实际上可能是非法的并且未由标准 according to the answer to this question 定义,因为等效表达式 return stream >> (*static_cast<char *>(static_cast<void *>(&type)));
在那里被声明为非法(或者更确切地说未由标准定义)。如果是这样的话,我需要这样做:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
char c = 0;
stream >> c;
type = static_cast<Type>(c);
return stream;
}
这不漂亮,是 4 行而不是 1 行等等。对于这样(看似)简单的事情,我觉得很不必要。
我的问题:在引用 enum class
时,通过 void*
的 reinterpret_cast
或等效 static_cast
是否真的非法(标准未定义)变量到其基础类型的引用?
您可以编写一个模板函数,允许您为您定义的每个 operator>>
编写 1 行。
template <class UT, class S, class E> S& DeserializeEnumClassValue(S &s, E &e)
{
UT temp;
s >> temp;
e = static_cast<E>(temp);
return s;
}
然后像那样使用它:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return DeserializeEnumClassValue<char>(stream, value);
}
但这可以使用 std::underlying_type (https://en.cppreference.com/w/cpp/types/underlying_type) 进行改进,因为可以在编译时获取它。
如果你采用这种方法,那么你也应该为 operator<<
做一些类似的事情以简化维护。
我得到以下解决方案:
template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type&
operator<<(QDataStream &s, const T &t)
{ return s << static_cast<typename std::underlying_type<T>::type>(t); }
template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type&
operator>>(QDataStream &s, T &t)
{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
来自github, and get verified in the src.
感觉人经常掉进语言的陷阱无法自拔themselves.If你用手填机器码,没问题,如果你不是wrong.I意思如果你很难想出一个反例,希望方便一些,并能容忍可能的错误,就it.Otherwise,用最安全的方法
我正在尝试序列化和反序列化(使用 QDataStream
但这与这里无关)一个 enum class
变量:
enum class Type : char
{
Trivial,
Complex
};
连载很简单:
QDataStream &operator<<(QDataStream &stream, Type type)
{
return stream << static_cast<char>(type);
}
但是反序列化不是:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return stream >> static_cast<char &>(type);
}
显然,static_cast
of reference to enum class
to a reference to its underlying type 是不允许的。此外, "obvious" 解决方案:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return stream >> reinterpret_cast<char &>(type);
}
实际上可能是非法的并且未由标准 according to the answer to this question 定义,因为等效表达式 return stream >> (*static_cast<char *>(static_cast<void *>(&type)));
在那里被声明为非法(或者更确切地说未由标准定义)。如果是这样的话,我需要这样做:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
char c = 0;
stream >> c;
type = static_cast<Type>(c);
return stream;
}
这不漂亮,是 4 行而不是 1 行等等。对于这样(看似)简单的事情,我觉得很不必要。
我的问题:在引用 enum class
时,通过 void*
的 reinterpret_cast
或等效 static_cast
是否真的非法(标准未定义)变量到其基础类型的引用?
您可以编写一个模板函数,允许您为您定义的每个 operator>>
编写 1 行。
template <class UT, class S, class E> S& DeserializeEnumClassValue(S &s, E &e)
{
UT temp;
s >> temp;
e = static_cast<E>(temp);
return s;
}
然后像那样使用它:
QDataStream &operator>>(QDataStream &stream, Type &type)
{
return DeserializeEnumClassValue<char>(stream, value);
}
但这可以使用 std::underlying_type (https://en.cppreference.com/w/cpp/types/underlying_type) 进行改进,因为可以在编译时获取它。
如果你采用这种方法,那么你也应该为 operator<<
做一些类似的事情以简化维护。
我得到以下解决方案:
template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type&
operator<<(QDataStream &s, const T &t)
{ return s << static_cast<typename std::underlying_type<T>::type>(t); }
template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream &>::type&
operator>>(QDataStream &s, T &t)
{ return s >> reinterpret_cast<typename std::underlying_type<T>::type &>(t); }
来自github, and get verified in the src.
感觉人经常掉进语言的陷阱无法自拔themselves.If你用手填机器码,没问题,如果你不是wrong.I意思如果你很难想出一个反例,希望方便一些,并能容忍可能的错误,就it.Otherwise,用最安全的方法