模板化QDataStream运算符<<对于枚举

时间:2017-03-18 00:10:35

标签: c++ qt

在本网站上的各种答案之后,我尝试定义自己的模板函数,将任何枚举值写入QDataStream。

template <typename T, typename std::enable_if_t<std::is_enum<T>::value>>
QDataStream &operator<<(QDataStream& stream, T enumValue)
{
    stream << static_cast<std::underlying_type_t<T>>(enumValue);
    return stream;
}

enum class MyEnum_e : int16_t{};

QDataStream stream;
MyEnum_e value;
stream << value; // Doesn't work

但我无法让它发挥作用。编译失败,并显示以下消息:

  

不匹配&#39;运营商&lt;&lt;&#39; (操作数类型是&#39; QDataStream&#39;和   &#39; MyEnum_e&#39;)流&lt;&lt;值;

为每个枚举定义函数我按预期工作。我使用enable_if错了吗?

3 个答案:

答案 0 :(得分:3)

您需要enable_if_t作为模板参数的默认值。

template <typename T, typename U=std::enable_if_t<std::is_enum<T>::value>>
QDataStream &operator<<(QDataStream& stream, T enumValue)
{
    stream << static_cast<std::underlying_type_t<T>>(enumValue);
    return stream;
}

答案 1 :(得分:0)

解决方案from aschepler above是C ++ 14。以下解决方案均适用于C ++ 11。

1。根据aschepler的回答:

template <typename T, typename U=std::enable_if<std::is_enum<T>::value>>
QDataStream &operator<<(QDataStream& stream, T enumValue)
{
    using underlying_type_t = typename std::underlying_type<T>::type;
    stream << static_cast<underlying_type_t>(enumValue);
    return stream;
}

请参见此处,此处不需要enable_if_tenable_if就足够了。

aschepler在他的第一句话中提到的使用C ++ 11时,请勿使用此解决方案。

2。下一个解决方案基于返回类型

返回类型???是的,您可能希望在参数上使用enable_if,但不适用于运算符重载:请参见cppreference

  

std :: enable_if可用作附加函数参数(不适用于运算符重载),返回类型(不适用于构造函数和析构函数)或用作类模板或函数模板参数。

template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream&>::type
operator<<(QDataStream& stream, T enumValue)
{
    using underlying_type_t = typename std::underlying_type<T>::type;
    stream << static_cast<underlying_type_t>(enumValue);
    return stream;
}

请注意,此处typename std::enable_if<...>::type是必需的,因为需要返回类型。

答案 2 :(得分:0)

由于我是在尝试将enum Type : quint8 {...}QSettings进行流传输时发现此问题的,因此这两种方法都是完整的。


template<class T, typename std::enable_if<std::is_enum<T>::value, T>::type* = nullptr>
QDataStream &operator<<(QDataStream& stream, const T &enumValue)
{
    return stream << static_cast<std::underlying_type_t<T>>(enumValue);
}

template<class T, typename std::enable_if<std::is_enum<T>::value, T>::type* = nullptr>
QDataStream &operator>>(QDataStream& stream, T &enumValue)
{
    std::underlying_type_t<T> val;
    stream >> val;
    enumValue = static_cast<T>(val);
    return stream;
}

对于QSettings类型enum,流操作符也必须在Qt元对象系统中注册。枚举用Q_ENUM()(在QObjectQ_GADGET中)或Q_ENUM_NS()(在命名空间中)或其他情况下的QT_DECLARE_METATYPE()注册。流操作符需要分别向qRegisterMetaTypeStreamOperators<Type>("Type")注册。还要注意,对于QFlags,已经定义了流运算符,但是AFAIK仍需要向qRegisterMetaTypeStreamOperators注册它们才能自动流传输。