diff --git a/src/blackmisc/compare.h b/src/blackmisc/compare.h index b93565edd..32584510b 100644 --- a/src/blackmisc/compare.h +++ b/src/blackmisc/compare.h @@ -56,6 +56,7 @@ namespace BlackMisc } template static bool baseEquals(const T *a, const T *b) { return *a == *b; } static bool baseEquals(const void *, const void *) { return true; } + static bool baseEquals(const CEmpty *, const CEmpty *) { return true; } }; /*! @@ -107,6 +108,7 @@ namespace BlackMisc } template static bool baseLess(const T *a, const T *b) { return *a < *b; } static bool baseLess(const void *, const void *) { return false; } + static bool baseLess(const CEmpty *, const CEmpty *) { return false; } }; /*! @@ -130,6 +132,7 @@ namespace BlackMisc } template static int baseCompare(const T *a, const T *b) { return compare(*a, *b); } static int baseCompare(const void *, const void *) { return 0; } + static int baseCompare(const CEmpty *, const CEmpty *) { return 0; } }; } // Mixin diff --git a/src/blackmisc/dbus.h b/src/blackmisc/dbus.h index d59a34b36..f8cb9650c 100644 --- a/src/blackmisc/dbus.h +++ b/src/blackmisc/dbus.h @@ -84,6 +84,8 @@ namespace BlackMisc template static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg); } static void baseMarshall(const void *, QDBusArgument &) {} static void baseUnmarshall(void *, const QDBusArgument &) {} + static void baseMarshall(const CEmpty *, QDBusArgument &) {} + static void baseUnmarshall(CEmpty *, const QDBusArgument &) {} }; /*! diff --git a/src/blackmisc/dictionary.h b/src/blackmisc/dictionary.h index 01492f485..695d029fe 100644 --- a/src/blackmisc/dictionary.h +++ b/src/blackmisc/dictionary.h @@ -18,6 +18,7 @@ #include "iterator.h" #include "range.h" #include "containerbase.h" +#include "typetraits.h" #include #include #include @@ -27,29 +28,6 @@ namespace BlackMisc namespace Private { //! \cond PRIVATE - - namespace ADL - { - struct NotFound {}; - struct FromAny { template FromAny(const T &); }; - NotFound operator <(const FromAny &, const FromAny &); - NotFound operator ==(const FromAny &, const FromAny &); - NotFound qHash(...); - using ::BlackMisc::qHash; // bring hidden name into scope - - template - constexpr static bool supportsQHash() - { - return ! std::is_same() == std::declval()), NotFound>::value && - ! std::is_same())), NotFound>::value; - }; - template - constexpr static bool supportsQMap() - { - return ! std::is_same() < std::declval()), NotFound>::value; - }; - } - template struct AssociativityTraits { @@ -75,7 +53,7 @@ namespace BlackMisc //! Trait to select the appropriate default associative container type depending on what the key type supports template - using DefaultAssociativeType = typename Private::AssociativityTraits(), Private::ADL::supportsQMap()>::template DefaultType; + using DefaultAssociativeType = typename Private::AssociativityTraits::value, ModelsQMapKey::value>::template DefaultType; //! Associative container with value semantics, chooses a sensible default implementation container type template class Impl = DefaultAssociativeType> @@ -495,6 +473,7 @@ namespace BlackMisc template static uint baseHash(const T *base) { return qHash(*base); } static uint baseHash(const void *) { return 0; } + static uint baseHash(const CEmpty *) { return 0; } }; } diff --git a/src/blackmisc/inheritancetraits.h b/src/blackmisc/inheritancetraits.h index 4ec97460a..e8eff4867 100644 --- a/src/blackmisc/inheritancetraits.h +++ b/src/blackmisc/inheritancetraits.h @@ -12,35 +12,36 @@ #ifndef BLACKMISC_INHERITANCE_TRAITS_H #define BLACKMISC_INHERITANCE_TRAITS_H +#include "typetraits.h" #include #include namespace BlackMisc { - class CEmpty; + class CPropertyIndex; /*! * If T has a member typedef base_type, this trait will obtain it, otherwise void. */ - template - class BaseOf + template > + struct BaseOf { - //template static typename U::base_type *test(int); - template static typename U::base_type *test(std::enable_if_t::value, int>); - template static void *test(...); - - public: - //! The declared base_type of T, or void if there is none. - using type = std::remove_pointer_t(0))>; + using type = void; //!< void }; + //! \cond + template + struct BaseOf> + { + using type = typename T::base_type; //!< T::base_type + }; + //! \endcond /*! * It T has a member typedef base_type which is a registered metatype, this trait will obtain it, otherwise void. */ template - class MetaBaseOf + struct MetaBaseOf { - public: //! Type of T::base_type, or void if not declared. using type = std::conditional_t::type>::Defined, typename BaseOf::type, void>; }; @@ -48,22 +49,18 @@ namespace BlackMisc /*! * If T has a member typedef base_type which has a member propertyByIndex, this trait will obtain it, otherwise void. */ - template - class IndexBaseOf + template > + struct IndexBaseOf { - // http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector - struct Empty {}; - struct Fallback { int propertyByIndex; }; - template struct int_t { using type = int; }; - template struct Derived : public Fallback, public std::conditional_t::value, Empty, U> {}; - - 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. - using type = decltype(test::type>(0)); + using type = void; //!< void }; + //! \cond + template + struct IndexBaseOf().propertyByIndex(std::declval()))>> + { + using type = typename T::base_type; //!< T::base_type + }; + //! \endcond /*! * Alias for typename BaseOf::type. diff --git a/src/blackmisc/json.h b/src/blackmisc/json.h index 788fbe680..8992a6fa8 100644 --- a/src/blackmisc/json.h +++ b/src/blackmisc/json.h @@ -282,6 +282,8 @@ namespace BlackMisc template static void baseConvertFromJson(T *base, const QJsonObject &json) { base->convertFromJson(json); } static QJsonObject baseToJson(const void *) { return {}; } static void baseConvertFromJson(void *, const QJsonObject &) {} + static QJsonObject baseToJson(const CEmpty *) { return {}; } + static void baseConvertFromJson(CEmpty *, const QJsonObject &) {} }; /*! diff --git a/src/blackmisc/logcategorylist.h b/src/blackmisc/logcategorylist.h index d772cb697..963f4a3a8 100644 --- a/src/blackmisc/logcategorylist.h +++ b/src/blackmisc/logcategorylist.h @@ -16,6 +16,7 @@ #include "logcategory.h" #include "sequence.h" #include "collection.h" +#include "typetraits.h" #include #include #include @@ -23,21 +24,6 @@ namespace BlackMisc { - namespace Private - { - //! \private Trait to detect whether a class T has a member function called getLogCategories - template class HasGetLogCategories - { - struct Base { int getLogCategories; }; - struct Derived : T, Base {}; - template struct TypeCheck {}; - template static std::false_type test(TypeCheck *); - template static std::true_type test(...); - public: - using type = decltype(test(nullptr)); - }; - } - /*! * A sequence of log categories. */ @@ -117,7 +103,7 @@ namespace BlackMisc static QThreadStorage list; if (! list.hasLocalData()) { - list.localData().appendCategoriesFromMemberFunction(tag(), typename Private::HasGetLogCategories::type()); + list.localData().appendCategoriesFromMemberFunction(tag(), HasGetLogCategories()); list.localData().appendCategoriesFromMetaType(tag(), std::integral_constant::Defined>()); list.localData().appendCategoriesFromMetaObject(tag(), std::is_base_of()); if (list.localData().isEmpty()) { list.localData().push_back(CLogCategory::uncategorized()); } diff --git a/src/blackmisc/statusmessage.h b/src/blackmisc/statusmessage.h index c66c980dc..ec4971190 100644 --- a/src/blackmisc/statusmessage.h +++ b/src/blackmisc/statusmessage.h @@ -17,6 +17,7 @@ #include "propertyindex.h" #include "logcategorylist.h" #include "timestampbased.h" +#include "typetraits.h" #include namespace BlackMisc @@ -29,25 +30,6 @@ namespace BlackMisc BLACKMISC_EXPORT QString arg(const QString &format, const QStringList &args); } - /*! - * Trait to detect whether T contains a member toQString. - */ - template - class HasToQString - { - // http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector - struct Fallback { int toQString; }; - template struct int_t { using type = int; }; - template ::value> struct Derived : public U, public Fallback {}; - template struct Derived : public Fallback {}; - template static char test(typename int_t<&Derived::toQString>::type); - template static int test(...); - - public: - //! True if T contains a member toQString. - static const bool value = sizeof(test(0)) > 1; - }; - /*! * Status severities */ diff --git a/src/blackmisc/typetraits.h b/src/blackmisc/typetraits.h new file mode 100644 index 000000000..3aac5a10f --- /dev/null +++ b/src/blackmisc/typetraits.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2016 + * swift Project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, + * including this file, may be copied, modified, propagated, or distributed except according to the terms + * contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_TYPETRAITS_H +#define BLACKMISC_TYPETRAITS_H + +#if defined(Q_CC_CLANG) || (defined(Q_CC_GNU) && __GNUC__ >= 5) +#define BLACK_HAS_FIXED_CWG1558 +#endif + +namespace BlackMisc +{ + + //! \cond PRIVATE +#ifdef BLACK_HAS_FIXED_CWG1558 + // Own implementation of C++17 std::void_t, simple variadic alias + // template which is always void. Useful for expression SFINAE. + template + using void_t = void; +#else // Work around defect in the C++ standard + namespace Private + { + template + struct make_void { using type = void; }; + } + template + using void_t = typename Private::make_void::type; +#endif + //! \endcond + + /*! + * Trait to detect whether T contains a member function toQString. + */ + template > + struct HasToQString : public std::false_type {}; + //! \cond + template + struct HasToQString().toQString())>> : public std::true_type {}; + //! \endcond + + /*! + * Trait to detect whether a class T has a static member function named getLogCategories. + */ + template > + struct HasGetLogCategories : public std::false_type {}; + //! \cond + template + struct HasGetLogCategories> : public std::true_type {}; + //! \endcond + + /*! + * Trait to detect whether a class T can be used as a key in a QHash. + */ + template > + struct ModelsQHashKey : public std::false_type {}; + //! \cond + template + struct ModelsQHashKey() == std::declval(), qHash(std::declval()))>> : public std::true_type {}; + //! \endcond + + /*! + * Trait to detect whether a class T can be used as a key in a QMap. + */ + template > + struct ModelsQMapKey : public std::false_type {}; + //! \cond + template + struct ModelsQMapKey() < std::declval())>> : public std::true_type {}; + //! \endcond + +} + +#endif