diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2023-09-24 22:08:50 +0200 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2023-09-26 22:32:51 +0200 |
commit | 35878fa924d0598b1cdec5ba358e8488f6774676 (patch) | |
tree | 9b6c2cc9f4f254642351e7f88a2590682e1d67f5 /src/corelib/global/qxptype_traits.h | |
parent | bf7732baca43537b11ba8989d7e68fa9a9a6696d (diff) |
Long live qxp::is_virtual_base_of
To be used in QWeakPointer.
Change-Id: I5ee9dd0862a0b23d316aaadf5d68bef1ce609e8b
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/global/qxptype_traits.h')
-rw-r--r-- | src/corelib/global/qxptype_traits.h | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/src/corelib/global/qxptype_traits.h b/src/corelib/global/qxptype_traits.h index 7da0478583..d1641e1d0d 100644 --- a/src/corelib/global/qxptype_traits.h +++ b/src/corelib/global/qxptype_traits.h @@ -1,4 +1,4 @@ -// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com> +// Copyright (C) 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>, Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only @@ -6,6 +6,7 @@ #define QXPTYPE_TRAITS_H #include <QtCore/qtconfigmacros.h> +#include <QtCore/qcompilerdetection.h> #include <type_traits> @@ -55,6 +56,63 @@ using is_detected = typename _detail::detector<qxp::nonesuch, void, Op, Args...> template <template <typename...> class Op, typename...Args> constexpr inline bool is_detected_v = is_detected<Op, Args...>::value; + +// qxp::is_virtual_base_of_v<B, D> is true if and only if B is a virtual base class of D. +// Just like is_base_of: +// * only works on complete types; +// * B and D must be class types; +// * ignores cv-qualifications; +// * B may be inaccessibile. + +namespace _detail { + // Check that From* can be converted to To*, ignoring accessibility. + // This can be done using a C cast (see [expr.cast]/4). +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wold-style-cast") +QT_WARNING_DISABLE_CLANG("-Wold-style-cast") + template <typename From, typename To> + using is_virtual_base_conversion_test = decltype( + (To *)std::declval<From *>() + ); +QT_WARNING_POP + + template <typename Base, typename Derived, typename = void> + struct is_virtual_base_of : std::false_type {}; + + template <typename Base, typename Derived> + struct is_virtual_base_of< + Base, Derived, + std::enable_if_t< + std::conjunction_v< + // Base is a base class of Derived. + std::is_base_of<Base, Derived>, + + // Check that Derived* can be converted to Base*, ignoring + // accessibility. If this is possible, then Base is + // an unambiguous base of Derived (=> virtual bases are always + // unambiguous). + qxp::is_detected<is_virtual_base_conversion_test, Derived, Base>, + + // Check that Base* can _not_ be converted to Derived*, + // again ignoring accessibility. This seals the deal: + // if this conversion cannot happen, it means that Base is an + // ambiguous base and/or it is a virtual base. + // But we have already established that Base is an unambiguous + // base, hence: Base is a virtual base. + std::negation< + qxp::is_detected<is_virtual_base_conversion_test, Base, Derived> + > + > + > + > : std::true_type {}; +} + +template <typename Base, typename Derived> +using is_virtual_base_of = _detail::is_virtual_base_of<std::remove_cv_t<Base>, std::remove_cv_t<Derived>>; + +template <typename Base, typename Derived> +constexpr inline bool is_virtual_base_of_v = is_virtual_base_of<Base, Derived>::value; + } // namespace qxp QT_END_NAMESPACE |