summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qtypeinfo.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/global/qtypeinfo.h')
-rw-r--r--src/corelib/global/qtypeinfo.h212
1 files changed, 17 insertions, 195 deletions
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index e6d63241bb..e9dfbc34a4 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -8,9 +8,7 @@
#include <QtCore/qcompilerdetection.h>
#include <QtCore/qcontainerfwd.h>
-#include <variant>
-#include <optional>
-#include <tuple>
+#include <type_traits>
QT_BEGIN_NAMESPACE
@@ -22,6 +20,13 @@ class QDebug;
namespace QtPrivate {
+// A trivially copyable class must also have a trivial, non-deleted
+// destructor [class.prop/1.3], CWG1734. Some implementations don't
+// check for a trivial destructor, because of backwards compatibility
+// with C++98's definition of trivial copyability.
+// Since trivial copiability has implications for the ABI, implementations
+// can't "just fix" their traits. So, although formally redundant, we
+// explicitly check for trivial destruction here.
template <typename T>
inline constexpr bool qIsRelocatable = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
@@ -97,6 +102,11 @@ public:
[[deprecated("Use std::is_pointer instead")]] static constexpr bool isPointer = false;
[[deprecated("Use std::is_integral instead")]] static constexpr bool isIntegral = false;
static constexpr bool isValueInitializationBitwiseZero = false;
+ static_assert(!isRelocatable ||
+ std::is_copy_constructible_v<T> ||
+ std::is_move_constructible_v<T>,
+ "All Ts... are Q_RELOCATABLE_TYPE, but T is neither copy- nor move-constructible, "
+ "so cannot be Q_RELOCATABLE_TYPE. Please mark T as Q_COMPLEX_TYPE manually.");
};
// QTypeInfo for std::pair:
@@ -158,6 +168,10 @@ public: \
isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral< TYPE >::value, \
isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero<TYPE>, \
}; \
+ static_assert(!isRelocatable || \
+ std::is_copy_constructible_v<TYPE > || \
+ std::is_move_constructible_v<TYPE >, \
+ #TYPE " is neither copy- nor move-constructible, so cannot be Q_RELOCATABLE_TYPE"); \
}
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \
@@ -169,197 +183,5 @@ template<typename T> class QFlags;
template<typename T>
Q_DECLARE_TYPEINFO_BODY(QFlags<T>, Q_PRIMITIVE_TYPE);
-namespace QTypeTraits
-{
-
-/*
- The templates below aim to find out whether one can safely instantiate an operator==() or
- operator<() for a type.
-
- This is tricky for containers, as most containers have unconstrained comparison operators, even though they
- rely on the corresponding operators for its content.
- This is especially true for all of the STL template classes that have a comparison operator defined, and
- leads to the situation, that the compiler would try to instantiate the operator, and fail if any
- of its template arguments does not have the operator implemented.
-
- The code tries to cover the relevant cases for Qt and the STL, by checking (recusrsively) the value_type
- of a container (if it exists), and checking the template arguments of pair, tuple and variant.
-*/
-namespace detail {
-
-// find out whether T is a conteiner
-// this is required to check the value type of containers for the existence of the comparison operator
-template <typename, typename = void>
-struct is_container : std::false_type {};
-template <typename T>
-struct is_container<T, std::void_t<
- typename T::value_type,
- std::is_convertible<decltype(std::declval<T>().begin() != std::declval<T>().end()), bool>
->> : std::true_type {};
-
-
-// Checks the existence of the comparison operator for the class itself
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_FLOAT_COMPARE
-template <typename, typename = void>
-struct has_operator_equal : std::false_type {};
-template <typename T>
-struct has_operator_equal<T, std::void_t<decltype(bool(std::declval<const T&>() == std::declval<const T&>()))>>
- : std::true_type {};
-QT_WARNING_POP
-
-// Two forward declarations
-template<typename T, bool = is_container<T>::value>
-struct expand_operator_equal_container;
-template<typename T>
-struct expand_operator_equal_tuple;
-
-// the entry point for the public method
-template<typename T>
-using expand_operator_equal = expand_operator_equal_container<T>;
-
-// if T isn't a container check if it's a tuple like object
-template<typename T, bool>
-struct expand_operator_equal_container : expand_operator_equal_tuple<T> {};
-// if T::value_type exists, check first T::value_type, then T itself
-template<typename T>
-struct expand_operator_equal_container<T, true> :
- std::conjunction<
- std::disjunction<
- std::is_same<T, typename T::value_type>, // avoid endless recursion
- expand_operator_equal<typename T::value_type>
- >, expand_operator_equal_tuple<T>> {};
-
-// recursively check the template arguments of a tuple like object
-template<typename ...T>
-using expand_operator_equal_recursive = std::conjunction<expand_operator_equal<T>...>;
-
-template<typename T>
-struct expand_operator_equal_tuple : has_operator_equal<T> {};
-template<typename T>
-struct expand_operator_equal_tuple<std::optional<T>> : has_operator_equal<T> {};
-template<typename T1, typename T2>
-struct expand_operator_equal_tuple<std::pair<T1, T2>> : expand_operator_equal_recursive<T1, T2> {};
-template<typename ...T>
-struct expand_operator_equal_tuple<std::tuple<T...>> : expand_operator_equal_recursive<T...> {};
-template<typename ...T>
-struct expand_operator_equal_tuple<std::variant<T...>> : expand_operator_equal_recursive<T...> {};
-
-// the same for operator<(), see above for explanations
-template <typename, typename = void>
-struct has_operator_less_than : std::false_type{};
-template <typename T>
-struct has_operator_less_than<T, std::void_t<decltype(bool(std::declval<const T&>() < std::declval<const T&>()))>>
- : std::true_type{};
-
-template<typename T, bool = is_container<T>::value>
-struct expand_operator_less_than_container;
-template<typename T>
-struct expand_operator_less_than_tuple;
-
-template<typename T>
-using expand_operator_less_than = expand_operator_less_than_container<T>;
-
-template<typename T, bool>
-struct expand_operator_less_than_container : expand_operator_less_than_tuple<T> {};
-template<typename T>
-struct expand_operator_less_than_container<T, true> :
- std::conjunction<
- std::disjunction<
- std::is_same<T, typename T::value_type>,
- expand_operator_less_than<typename T::value_type>
- >, expand_operator_less_than_tuple<T>
- > {};
-
-template<typename ...T>
-using expand_operator_less_than_recursive = std::conjunction<expand_operator_less_than<T>...>;
-
-template<typename T>
-struct expand_operator_less_than_tuple : has_operator_less_than<T> {};
-template<typename T>
-struct expand_operator_less_than_tuple<std::optional<T>> : has_operator_less_than<T> {};
-template<typename T1, typename T2>
-struct expand_operator_less_than_tuple<std::pair<T1, T2>> : expand_operator_less_than_recursive<T1, T2> {};
-template<typename ...T>
-struct expand_operator_less_than_tuple<std::tuple<T...>> : expand_operator_less_than_recursive<T...> {};
-template<typename ...T>
-struct expand_operator_less_than_tuple<std::variant<T...>> : expand_operator_less_than_recursive<T...> {};
-
-}
-
-template<typename T, typename = void>
-struct is_dereferenceable : std::false_type {};
-
-template<typename T>
-struct is_dereferenceable<T, std::void_t<decltype(std::declval<T>().operator->())> >
- : std::true_type {};
-
-template <typename T>
-inline constexpr bool is_dereferenceable_v = is_dereferenceable<T>::value;
-
-template<typename T>
-struct has_operator_equal : detail::expand_operator_equal<T> {};
-template<typename T>
-inline constexpr bool has_operator_equal_v = has_operator_equal<T>::value;
-
-template <typename Container, typename T>
-using has_operator_equal_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_equal<T>>;
-
-template<typename T>
-struct has_operator_less_than : detail::expand_operator_less_than<T> {};
-template<typename T>
-inline constexpr bool has_operator_less_than_v = has_operator_less_than<T>::value;
-
-template <typename Container, typename T>
-using has_operator_less_than_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_operator_less_than<T>>;
-
-template <typename ...T>
-using compare_eq_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal<T>...>, bool>;
-
-template <typename Container, typename ...T>
-using compare_eq_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_equal_container<Container, T>...>, bool>;
-
-template <typename ...T>
-using compare_lt_result = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than<T>...>, bool>;
-
-template <typename Container, typename ...T>
-using compare_lt_result_container = std::enable_if_t<std::conjunction_v<QTypeTraits::has_operator_less_than_container<Container, T>...>, bool>;
-
-namespace detail {
-
-template<typename T>
-const T &const_reference();
-template<typename T>
-T &reference();
-
-}
-
-template <typename Stream, typename, typename = void>
-struct has_ostream_operator : std::false_type {};
-template <typename Stream, typename T>
-struct has_ostream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() << detail::const_reference<T>())>>
- : std::true_type {};
-template <typename Stream, typename T>
-inline constexpr bool has_ostream_operator_v = has_ostream_operator<Stream, T>::value;
-
-template <typename Stream, typename Container, typename T>
-using has_ostream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_ostream_operator<Stream, T>>;
-
-template <typename Stream, typename, typename = void>
-struct has_istream_operator : std::false_type {};
-template <typename Stream, typename T>
-struct has_istream_operator<Stream, T, std::void_t<decltype(detail::reference<Stream>() >> detail::reference<T>())>>
- : std::true_type {};
-template <typename Stream, typename T>
-inline constexpr bool has_istream_operator_v = has_istream_operator<Stream, T>::value;
-template <typename Stream, typename Container, typename T>
-using has_istream_operator_container = std::disjunction<std::is_base_of<Container, T>, QTypeTraits::has_istream_operator<Stream, T>>;
-
-template <typename Stream, typename T>
-inline constexpr bool has_stream_operator_v = has_ostream_operator_v<Stream, T> && has_istream_operator_v<Stream, T>;
-
-}
-
-
QT_END_NAMESPACE
#endif // QTYPEINFO_H