1// 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>
2// Copyright (C) 2022 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#ifndef QXPTYPE_TRAITS_H
6#define QXPTYPE_TRAITS_H
7
8#include <QtCore/qtconfigmacros.h>
9#include <QtCore/qcompilerdetection.h>
10
11#include <type_traits>
12
13//
14// W A R N I N G
15// -------------
16//
17// This file is not part of the Qt API. Types and functions defined in this
18// file can reliably be replaced by their std counterparts, once available.
19// You may use these definitions in your own code, but be aware that we
20// will remove them once Qt depends on the C++ version that supports
21// them in namespace std. There will be NO deprecation warning, the
22// definitions will JUST go away.
23//
24// If you can't agree to these terms, don't use these definitions!
25//
26// We mean it.
27//
28
29QT_BEGIN_NAMESPACE
30
31// like std::experimental::{nonesuch,is_detected/_v}(LFTSv2)
32namespace qxp {
33
34struct nonesuch {
35 ~nonesuch() = delete;
36 nonesuch(const nonesuch&) = delete;
37 void operator=(const nonesuch&) = delete;
38};
39
40namespace _detail {
41 template <typename T, typename Void, template <typename...> class Op, typename...Args>
42 struct detector {
43 using value_t = std::false_type;
44 using type = T;
45 };
46 template <typename T, template <typename...> class Op, typename...Args>
47 struct detector<T, std::void_t<Op<Args...>>, Op, Args...> {
48 using value_t = std::true_type;
49 using type = Op<Args...>;
50 };
51} // namespace _detail
52
53template <template <typename...> class Op, typename...Args>
54using is_detected = typename _detail::detector<qxp::nonesuch, void, Op, Args...>::value_t;
55
56template <template <typename...> class Op, typename...Args>
57constexpr inline bool is_detected_v = is_detected<Op, Args...>::value;
58
59
60// qxp::is_virtual_base_of_v<B, D> is true if and only if B is a virtual base class of D.
61// Just like is_base_of:
62// * only works on complete types;
63// * B and D must be class types;
64// * ignores cv-qualifications;
65// * B may be inaccessibile.
66
67namespace _detail {
68 // Check that From* can be converted to To*, ignoring accessibility.
69 // This can be done using a C cast (see [expr.cast]/4).
70QT_WARNING_PUSH
71QT_WARNING_DISABLE_GCC("-Wold-style-cast")
72QT_WARNING_DISABLE_CLANG("-Wold-style-cast")
73 template <typename From, typename To>
74 using is_virtual_base_conversion_test = decltype(
75 (To *)std::declval<From *>()
76 );
77QT_WARNING_POP
78
79 template <typename Base, typename Derived, typename = void>
80 struct is_virtual_base_of : std::false_type {};
81
82 template <typename Base, typename Derived>
83 struct is_virtual_base_of<
84 Base, Derived,
85 std::enable_if_t<
86 std::conjunction_v<
87 // Base is a base class of Derived.
88 std::is_base_of<Base, Derived>,
89
90 // Check that Derived* can be converted to Base*, ignoring
91 // accessibility. If this is possible, then Base is
92 // an unambiguous base of Derived (=> virtual bases are always
93 // unambiguous).
94 qxp::is_detected<is_virtual_base_conversion_test, Derived, Base>,
95
96 // Check that Base* can _not_ be converted to Derived*,
97 // again ignoring accessibility. This seals the deal:
98 // if this conversion cannot happen, it means that Base is an
99 // ambiguous base and/or it is a virtual base.
100 // But we have already established that Base is an unambiguous
101 // base, hence: Base is a virtual base.
102 std::negation<
103 qxp::is_detected<is_virtual_base_conversion_test, Base, Derived>
104 >
105 >
106 >
107 > : std::true_type {};
108}
109
110template <typename Base, typename Derived>
111using is_virtual_base_of = _detail::is_virtual_base_of<std::remove_cv_t<Base>, std::remove_cv_t<Derived>>;
112
113template <typename Base, typename Derived>
114constexpr inline bool is_virtual_base_of_v = is_virtual_base_of<Base, Derived>::value;
115
116} // namespace qxp
117
118QT_END_NAMESPACE
119
120#endif // QXPTYPE_TRAITS_H
121
122