From 0ebe21a7cf49243cfe58f92618b0f1b39736e25e Mon Sep 17 00:00:00 2001 From: Mat Sutcliffe Date: Sun, 18 Apr 2021 17:50:41 +0100 Subject: [PATCH] Use `if constexpr` in metaclass visitor functions --- src/blackmisc/metaclass.h | 27 ++------------- src/blackmisc/mixin/mixincompare.h | 27 +++++++++++---- src/blackmisc/mixin/mixindatastream.h | 18 +++++++--- src/blackmisc/mixin/mixindbus.h | 36 ++++++++++--------- src/blackmisc/mixin/mixinhash.h | 9 +++-- src/blackmisc/mixin/mixinjson.h | 40 ++++++++++++---------- src/blackmisc/simulation/aircraftmodel.cpp | 20 ++++++----- 7 files changed, 98 insertions(+), 79 deletions(-) diff --git a/src/blackmisc/metaclass.h b/src/blackmisc/metaclass.h index baf36aa1a..528c79601 100644 --- a/src/blackmisc/metaclass.h +++ b/src/blackmisc/metaclass.h @@ -12,7 +12,6 @@ #define BLACKMISC_METACLASS_H #include "blackmisc/invoke.h" -#include "blackmisc/integersequence.h" #include #include #include @@ -169,7 +168,7 @@ namespace BlackMisc //! True if m_flags contains all flags. template - constexpr bool has(Flags2 flags) const { return (MetaFlags() & flags) == flags; } + static constexpr bool has(Flags2 flags) { return (MetaFlags() & flags) == flags; } //! Invoke the member on an instance of the value class. template @@ -266,34 +265,12 @@ namespace BlackMisc class CMetaClassIntrospector { public: - //! Return a CMetaClassIntrospector covering only those members which have the given flags. - //! \see BlackMisc::MetaFlags - template - constexpr static auto with(Flags) { return filter(MaskSequence<(members().at(index()).has(Flags()))...>()); } - - //! Return a CMetaClassIntrospector covering only those members which do not have the given flags. - //! \see BlackMisc::MetaFlags - template - constexpr static auto without(Flags) { return filter(MaskSequence<(! members().at(index()).has(Flags()))...>()); } - //! For each metamember in metaclass, pass metamember as argument to visitor function. template static void forEachMember(F &&visitor) { - (static_cast(std::forward(visitor)(members().at(index()))), ...); + (static_cast(std::forward(visitor)(MetaClass::getMemberList().at(std::integral_constant()))), ...); } - - private: - template - using MaskSequence = Private::MaskSequence, Mask...>; - - template - constexpr static auto filter(std::index_sequence) { return CMetaClassIntrospector(); } - - template - using index = std::integral_constant; - - constexpr static auto members() { return MetaClass::getMemberList(); } }; // *INDENT-ON* diff --git a/src/blackmisc/mixin/mixincompare.h b/src/blackmisc/mixin/mixincompare.h index e3fd7d193..8699b74b7 100644 --- a/src/blackmisc/mixin/mixincompare.h +++ b/src/blackmisc/mixin/mixincompare.h @@ -58,9 +58,14 @@ namespace BlackMisc private: static bool equals(const Derived &a, const Derived &b) { - constexpr auto meta = introspect().without(MetaFlags()); bool result = baseEquals(static_cast *>(&a), static_cast *>(&b)); - meta.forEachMember([ & ](auto member) { result = result && EqualsByMetaClass::membersEqual(member.in(a), member.in(b), member.m_flags); }); + introspect().forEachMember([ & ](auto member) + { + if constexpr (!decltype(member)::has(MetaFlags())) + { + result = result && EqualsByMetaClass::membersEqual(member.in(a), member.in(b), member.m_flags); + } + }); return result; } template static bool baseEquals(const T *a, const T *b) { return *a == *b; } @@ -119,10 +124,15 @@ namespace BlackMisc private: static bool less(const Derived &a, const Derived &b) { - constexpr auto meta = introspect().without(MetaFlags()); bool result = baseLess(static_cast *>(&a), static_cast *>(&b)); bool gt = baseLess(static_cast *>(&b), static_cast *>(&a)); - meta.forEachMember([ & ](auto member) { result = result || LessThanByMetaClass::membersLess(gt, member.in(a), member.in(b), member.m_flags); }); + introspect().forEachMember([ & ](auto member) + { + if constexpr (!decltype(member)::has(MetaFlags())) + { + result = result || LessThanByMetaClass::membersLess(gt, member.in(a), member.in(b), member.m_flags); + } + }); return result; } template static bool baseLess(const T *a, const T *b) { return *a < *b; } @@ -155,9 +165,14 @@ namespace BlackMisc private: static int compareImpl(const Derived &a, const Derived &b) { - constexpr auto meta = introspect().without(MetaFlags()); int result = baseCompare(static_cast *>(&a), static_cast *>(&b)); - meta.forEachMember([ & ](auto member) { result = result ? result : CompareByMetaClass::membersCompare(member.in(a), member.in(b), member.m_flags); }); + introspect().forEachMember([ & ](auto member) + { + if constexpr (!decltype(member)::has(MetaFlags())) + { + result = result ? result : CompareByMetaClass::membersCompare(member.in(a), member.in(b), member.m_flags); + } + }); return result; } template static int baseCompare(const T *a, const T *b) { return compare(*a, *b); } diff --git a/src/blackmisc/mixin/mixindatastream.h b/src/blackmisc/mixin/mixindatastream.h index 64a23951d..3f2a871ea 100644 --- a/src/blackmisc/mixin/mixindatastream.h +++ b/src/blackmisc/mixin/mixindatastream.h @@ -58,16 +58,26 @@ namespace BlackMisc void marshalToDataStream(QDataStream &stream) const { baseMarshal(static_cast *>(derived()), stream); - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ &, this ](auto member) { stream << member.in(*this->derived()); }); + introspect().forEachMember([ &, this ](auto member) + { + if constexpr (!decltype(member)::has(MetaFlags())) + { + stream << member.in(*this->derived()); + } + }); } //! Unmarshal a value from a QDataStream. void unmarshalFromDataStream(QDataStream &stream) { baseUnmarshal(static_cast *>(derived()), stream); - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ &, this ](auto member) { stream >> member.in(*this->derived()); }); + introspect().forEachMember([ &, this ](auto member) + { + if constexpr (!decltype(member)::has(MetaFlags())) + { + stream >> member.in(*this->derived()); + } + }); } private: diff --git a/src/blackmisc/mixin/mixindbus.h b/src/blackmisc/mixin/mixindbus.h index 2bac088f9..98a128899 100644 --- a/src/blackmisc/mixin/mixindbus.h +++ b/src/blackmisc/mixin/mixindbus.h @@ -71,19 +71,21 @@ namespace BlackMisc void marshallToDbus(QDBusArgument &arg, Tags...) const { baseMarshall(static_cast *>(derived()), arg); - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ &, this ](auto member) + introspect().forEachMember([ &, this ](auto member) { - const auto &value = member.in(*this->derived()); - if constexpr (THasMarshallMethods>::value) + if constexpr (!decltype(member)::has(MetaFlags())) { - if constexpr (member.has(MetaFlags())) + const auto &value = member.in(*this->derived()); + if constexpr (THasMarshallMethods>::value) { - value.marshallToDbus(arg, LosslessTag()); + if constexpr (member.has(MetaFlags())) + { + value.marshallToDbus(arg, LosslessTag()); + } + else { value.marshallToDbus(arg); } } - else { value.marshallToDbus(arg); } + else { arg << value; } } - else { arg << value; } }); } @@ -91,19 +93,21 @@ namespace BlackMisc void unmarshallFromDbus(const QDBusArgument &arg, Tags...) { baseUnmarshall(static_cast *>(derived()), arg); - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ &, this ](auto member) + introspect().forEachMember([ &, this ](auto member) { - auto &value = member.in(*this->derived()); - if constexpr (THasMarshallMethods>::value) + if constexpr (!decltype(member)::has(MetaFlags())) { - if constexpr (member.has(MetaFlags())) + auto &value = member.in(*this->derived()); + if constexpr (THasMarshallMethods>::value) { - value.unmarshallFromDbus(arg, LosslessTag()); + if constexpr (member.has(MetaFlags())) + { + value.unmarshallFromDbus(arg, LosslessTag()); + } + else { value.unmarshallFromDbus(arg); } } - else { value.unmarshallFromDbus(arg); } + else { arg >> value; } } - else { arg >> value; } }); } diff --git a/src/blackmisc/mixin/mixinhash.h b/src/blackmisc/mixin/mixinhash.h index 82abed4a4..4f165f67b 100644 --- a/src/blackmisc/mixin/mixinhash.h +++ b/src/blackmisc/mixin/mixinhash.h @@ -60,8 +60,13 @@ namespace BlackMisc static uint hashImpl(const Derived &value) { uint hash = baseHash(static_cast *>(&value)); - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ & ](const auto &member) { hash ^= qHash(member.in(value)); }); + introspect().forEachMember([ & ](auto member) + { + if constexpr (!decltype(member)::has(MetaFlags())) + { + hash ^= qHash(member.in(value)); + } + }); return hash; } diff --git a/src/blackmisc/mixin/mixinjson.h b/src/blackmisc/mixin/mixinjson.h index 92b46b757..47bceee83 100644 --- a/src/blackmisc/mixin/mixinjson.h +++ b/src/blackmisc/mixin/mixinjson.h @@ -96,10 +96,12 @@ namespace BlackMisc QJsonObject toJson() const { QJsonObject json; - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ &, this ](auto member) + introspect().forEachMember([ &, this ](auto member) { - json << std::make_pair(CExplicitLatin1String(member.latin1Name()), std::cref(member.in(*this->derived()))); + if constexpr (!decltype(member)::has(MetaFlags())) + { + json << std::make_pair(CExplicitLatin1String(member.latin1Name()), std::cref(member.in(*this->derived()))); + } }); return Json::appendJsonObject(json, baseToJson(static_cast *>(derived()))); } @@ -115,23 +117,25 @@ namespace BlackMisc void convertFromJson(const QJsonObject &json) { baseConvertFromJson(static_cast *>(derived()), json); - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ &, this ](auto member) + introspect().forEachMember([ &, this ](auto member) { - const auto value = json.value(CExplicitLatin1String(member.latin1Name())); - if (value.isUndefined()) + if constexpr (!decltype(member)::has(MetaFlags())) { - constexpr bool required = false; //! \fixme add RequiredForJson flag in metaclass system - // cppcheck-suppress knownConditionTrueFalse - // QLatin1String used instead of QStringLiteral below since the latter causes an internal compiler bug - // in GCC 8 and higher - if (required) { throw CJsonException(QLatin1String("Missing required member '%1'").arg(member.latin1Name())); } - } - else - { - CJsonScope scope(member.latin1Name()); - Q_UNUSED(scope); - value >> member.in(*this->derived()); + const auto value = json.value(CExplicitLatin1String(member.latin1Name())); + if (value.isUndefined()) + { + constexpr bool required = false; //! \fixme add RequiredForJson flag in metaclass system + // cppcheck-suppress knownConditionTrueFalse + // QLatin1String used instead of QStringLiteral below since the latter causes an internal compiler bug + // in GCC 8 and higher + if (required) { throw CJsonException(QLatin1String("Missing required member '%1'").arg(member.latin1Name())); } + } + else + { + CJsonScope scope(member.latin1Name()); + Q_UNUSED(scope); + value >> member.in(*this->derived()); + } } }); } diff --git a/src/blackmisc/simulation/aircraftmodel.cpp b/src/blackmisc/simulation/aircraftmodel.cpp index b550d98bf..a26205d2b 100644 --- a/src/blackmisc/simulation/aircraftmodel.cpp +++ b/src/blackmisc/simulation/aircraftmodel.cpp @@ -125,22 +125,26 @@ namespace BlackMisc QJsonObject CAircraftModel::toMemoizedJson(MemoHelper::CMemoizer &helper) const { QJsonObject json; - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ &, this ](auto member) + introspect().forEachMember([ &, this ](auto member) { - auto &&maybeMemo = helper.maybeMemoize(member.in(*this)); - json << std::make_pair(CExplicitLatin1String(member.latin1Name()), std::cref(maybeMemo)); + if constexpr (!decltype(member)::has(MetaFlags())) + { + auto &&maybeMemo = helper.maybeMemoize(member.in(*this)); + json << std::make_pair(CExplicitLatin1String(member.latin1Name()), std::cref(maybeMemo)); + } }); return json; } void CAircraftModel::convertFromMemoizedJson(const QJsonObject &json, const MemoHelper::CUnmemoizer &helper) { - constexpr auto meta = introspect().without(MetaFlags()); - meta.forEachMember([ &, this ](auto member) + introspect().forEachMember([ &, this ](auto member) { - auto it = json.find(CExplicitLatin1String(member.latin1Name())); - if (it != json.end()) { it.value() >> helper.maybeUnmemoize(member.in(*this)).get(); } + if constexpr (!decltype(member)::has(MetaFlags())) + { + auto it = json.find(CExplicitLatin1String(member.latin1Name())); + if (it != json.end()) { it.value() >> helper.maybeUnmemoize(member.in(*this)).get(); } + } }); }