(取消)序列化枚举类



我正在尝试序列化和反序列化(使用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引用enum class引用其基础类型。此外,"显而易见"的解决方案:

QDataStream &operator>>(QDataStream &stream, Type &type)
{    
    return stream >> reinterpret_cast<char &>(type);
}

实际上可能是非法的,并且根据这个问题的答案,标准没有定义,因为等效的表达式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的引用强制转换为其基础类型的引用时,reinterpret_cast或等效的 via static_cast void* 真的是非法的(标准未定义)吗?

您可以编写一个模板函数,该函数允许您为定义的每个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 获得验证,并在 src 中得到验证。

我觉得人们经常陷入语言的陷阱,无法自拔。如果你用手填写机器码,没有问题,如果你没有错的话。我的意思是,如果你很难想出一个反例,希望有一些方便,可以容忍可能的错误,就去做吧。否则,使用最安全的方法。

相关内容

  • 没有找到相关文章

最新更新