Reputation: 1007
Following various answers on this site, I tried to define my own template function to write any enumeration value into a 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
But I can't get to make it work. Compilation fails with following message:
no match for 'operator<<' (operand types are 'QDataStream' and 'MyEnum_e') stream << value;
Defining the function for each individual enumeration I have works as expected. Am I using enable_if
wrong?
Upvotes: 3
Views: 1327
Reputation: 4867
Since I found this while trying to stream an enum Type : quint8 {...}
to & from QSettings
, here's both ways for completeness.
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;
}
Also for QSettings
the enum
type AND the stream operators must be registered in Qt meta object system. Enums are registered with the Q_ENUM()
(in QObject
or Q_GADGET
) or Q_ENUM_NS()
(in namespaces), or with QT_DECLARE_METATYPE()
in other cases. The stream operators need to be registered separately with qRegisterMetaTypeStreamOperators<Type>("Type")
. Also note that for QFlags
there are already streaming operators defined, but AFAIK they still need to be registered with qRegisterMetaTypeStreamOperators
to be streamed automatically.
UPDATE:
MSVC17 with C++14 didn't like my code above, so based on @DrumM's answer, here's what works for me now with that, MinGW 7.3, gcc 6.3 & 7.3:
template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream&>::type
operator<<(QDataStream& stream, const T &enumValue)
{
return stream << static_cast<std::underlying_type_t<T>>(enumValue);
}
template <typename T>
typename std::enable_if<std::is_enum<T>::value, QDataStream&>::type
operator>>(QDataStream& stream, T &enumValue)
{
std::underlying_type_t<T> val;
stream >> val;
enumValue = static_cast<T>(val);
return stream;
}
// ... later
qRegisterMetaTypeStreamOperators<MyScope::MyEnum>("MyScope::MyEnum");
Upvotes: 2
Reputation: 2825
The solution from aschepler above is C++14. The following solutions work both for C++11.
1. Based on aschepler's answer:
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;
}
See here that enable_if_t
is not needed here, enable_if
is sufficient.
Don't use this solution when using C++11 as mentioned by aschepler in his first comment.
2. The next solution is based using the return type
Return type?? Yes, you could expect to use enable_if
on the the argument, but it's not applicable to operator overloads: See at cppreference:
std::enable_if can be used as an additional function argument (not applicable to operator overloads), as a return type (not applicable to constructors and destructors), or as a class template or function template parameter.
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;
}
See that typename std::enable_if<...>::type
is necessary here because the type needs to be returned.
Upvotes: 1
Reputation: 72463
You need enable_if_t
to be the default value for a template parameter.
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;
}
Upvotes: 4