From dfe42e1ce7c9c28570332df8ae6178cfc518a6a1 Mon Sep 17 00:00:00 2001 From: Mathew Sutcliffe Date: Fri, 8 May 2015 20:19:54 +0100 Subject: [PATCH] refs #413, #416 Implemented base_type fallthrough in Mixin::Index so it can be used by more classes. (cherry picked from commit d97775a232b007061cbfa85b451b0be569127696) --- src/blackmisc/inheritance_traits.h | 26 ++++++++++++ src/blackmisc/pq/physicalquantity.cpp | 4 +- src/blackmisc/pq/physicalquantity.h | 2 +- src/blackmisc/propertyindexvariantmap.h | 54 ++++++++++++++++++------- 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/blackmisc/inheritance_traits.h b/src/blackmisc/inheritance_traits.h index d432e93b9..0c5f87a00 100644 --- a/src/blackmisc/inheritance_traits.h +++ b/src/blackmisc/inheritance_traits.h @@ -45,6 +45,26 @@ namespace BlackMisc typedef typename std::conditional::type>::Defined, typename BaseOf::type, void>::type type; }; + /*! + * If T has a member typedef base_type which has a member propertyByIndex, this trait will obtain it, otherwise void. + */ + template + class IndexBaseOf + { + // http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector + struct Empty {}; + struct Fallback { int propertyByIndex; }; + template struct int_t { typedef int type; }; + template struct Derived : public Fallback, public std::conditional::value, Empty, U>::type {}; + + template static void test(typename int_t<&Derived::propertyByIndex>::type); + template static U test(...); + + public: + //! Type of T::base_type, or void if not declared. + typedef decltype(test::type>(0)) type; + }; + /*! * Alias for typename BaseOf::type. */ @@ -56,6 +76,12 @@ namespace BlackMisc */ template using MetaBaseOfT = typename MetaBaseOf::type; + + /*! + * Alias for typename IndexBaseOf::type. + */ + template + using IndexBaseOfT = typename IndexBaseOf::type; } #endif diff --git a/src/blackmisc/pq/physicalquantity.cpp b/src/blackmisc/pq/physicalquantity.cpp index b9c77ec02..1eaa282c0 100644 --- a/src/blackmisc/pq/physicalquantity.cpp +++ b/src/blackmisc/pq/physicalquantity.cpp @@ -371,7 +371,7 @@ namespace BlackMisc case IndexValueRounded6DigitsWithUnit: return CVariant::from(this->valueRoundedWithUnit(6)); default: - return Mixin::Index>::propertyByIndex(index); + return Mixin::Index::propertyByIndex(index); } } @@ -400,7 +400,7 @@ namespace BlackMisc this->parseFromString(variant.toQString()); break; default: - Mixin::Index>::setPropertyByIndex(variant, index); + Mixin::Index::setPropertyByIndex(variant, index); break; } } diff --git a/src/blackmisc/pq/physicalquantity.h b/src/blackmisc/pq/physicalquantity.h index d0cbf48f6..b1143293c 100644 --- a/src/blackmisc/pq/physicalquantity.h +++ b/src/blackmisc/pq/physicalquantity.h @@ -45,7 +45,7 @@ namespace BlackMisc template class CPhysicalQuantity : public Mixin::DBusOperators>, public Mixin::JsonOperators>, - public Mixin::Index>, + public Mixin::Index, public Mixin::MetaTypeAndQList, public Mixin::String, public Mixin::Icon> diff --git a/src/blackmisc/propertyindexvariantmap.h b/src/blackmisc/propertyindexvariantmap.h index 7ed2ddaa2..ebc708a01 100644 --- a/src/blackmisc/propertyindexvariantmap.h +++ b/src/blackmisc/propertyindexvariantmap.h @@ -27,6 +27,7 @@ namespace BlackMisc namespace Mixin { + /*! * CRTP class template from which a derived class can inherit property indexing functions. * @@ -64,7 +65,39 @@ namespace BlackMisc private: const Derived *derived() const { return static_cast(this); } Derived *derived() { return static_cast(this); } + + template ::value, int>::type = 0> + CVariant myself() const { return CVariant::from(*derived()); } + template ::value, int>::type = 0> + void myself(const CVariant &variant) { *derived() = variant.to(); } + + template ::value, int>::type = 0> + CVariant myself() const { qFatal("isMyself should have been handled before reaching here"); return {}; } + template ::value, int>::type = 0> + void myself(const CVariant &) { qFatal("isMyself should have been handled before reaching here"); } + + template + CVariant basePropertyByIndex(const T *base, const CPropertyIndex &index) const { return base->propertyByIndex(index); } + template + void baseSetPropertyByIndex(T *base, const CVariant &var, const CPropertyIndex &index) { base->setPropertyByIndex(var, index); } + + CVariant basePropertyByIndex(const void *, const CPropertyIndex &index) const + { qFatal("%s", qPrintable("Property by index not found, index: " + index.toQString())); return {}; } + void baseSetPropertyByIndex(void *, const CVariant &, const CPropertyIndex &index) + { qFatal("%s", qPrintable("Property by index not found (setter), index: " + index.toQString())); } }; + + /*! + * When a derived class and a base class both inherit from Mixin::Index, + * the derived class uses this macro to disambiguate the inherited members. + */ +# define BLACKMISC_DECLARE_USING_MIXIN_INDEX(DERIVED) \ + using ::BlackMisc::Mixin::Index::apply; \ + using ::BlackMisc::Mixin::Index::setPropertyByIndex; \ + using ::BlackMisc::Mixin::Index::propertyByIndex; \ + using ::BlackMisc::Mixin::Index::propertyByIndexAsString; \ + using ::BlackMisc::Mixin::Index::equalsPropertyByIndex; + } // Mixin /*! @@ -227,20 +260,19 @@ namespace BlackMisc { if (index.isMyself()) { - derived()->convertFromCVariant(variant); - return; + myself(variant); + } + else + { + baseSetPropertyByIndex(static_cast *>(derived()), variant, index); } - - // not all classes have implemented nesting - const QString m = QString("Property by index not found (setter), index: ").append(index.toQString()); - qFatal("%s", qPrintable(m)); } template CVariant Index::propertyByIndex(const CPropertyIndex &index) const { if (index.isMyself()) { - return derived()->toCVariant(); + return myself(); } auto i = index.frontCasted(); switch (i) @@ -252,18 +284,12 @@ namespace BlackMisc case IndexString: return CVariant(derived()->toQString()); default: - break; + return basePropertyByIndex(static_cast *>(derived()), index); } - - // not all classes have implemented nesting - const QString m = QString("Property by index not found, index: ").append(index.toQString()); - qFatal("%s", qPrintable(m)); - return {}; } template QString Index::propertyByIndexAsString(const CPropertyIndex &index, bool i18n) const { - // default implementation, requires propertyByIndex return derived()->propertyByIndex(index).toQString(i18n); } template