diff options
Diffstat (limited to 'src/corelib/global/qtypeinfo.h')
-rw-r--r-- | src/corelib/global/qtypeinfo.h | 219 |
1 files changed, 21 insertions, 198 deletions
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h index b07c9f4afe..e9dfbc34a4 100644 --- a/src/corelib/global/qtypeinfo.h +++ b/src/corelib/global/qtypeinfo.h @@ -2,15 +2,14 @@ // Copyright (C) 2016 Intel Corporation. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only -#include <QtCore/qglobal.h> -#include <QtCore/qcontainerfwd.h> -#include <variant> -#include <optional> -#include <tuple> - #ifndef QTYPEINFO_H #define QTYPEINFO_H +#include <QtCore/qcompilerdetection.h> +#include <QtCore/qcontainerfwd.h> + +#include <type_traits> + QT_BEGIN_NAMESPACE class QDebug; @@ -21,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>; @@ -96,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: @@ -157,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) \ @@ -168,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 |