// 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 #ifndef QTTYPETRAITS_H #define QTTYPETRAITS_H #include #include #include #include #include #include #include #if 0 #pragma qt_class(QtTypeTraits) #pragma qt_sync_stop_processing #endif QT_BEGIN_NAMESPACE // like std::to_underlying template constexpr std::underlying_type_t qToUnderlying(Enum e) noexcept { return static_cast>(e); } #ifndef QT_NO_QASCONST #if QT_DEPRECATED_SINCE(6, 6) // this adds const to non-const objects (like std::as_const) template QT_DEPRECATED_VERSION_X_6_6("Use std::as_const() instead.") constexpr typename std::add_const::type &qAsConst(T &t) noexcept { return t; } // prevent rvalue arguments: template void qAsConst(const T &&) = delete; #endif // QT_DEPRECATED_SINCE(6, 6) #endif // QT_NO_QASCONST #ifndef QT_NO_QEXCHANGE // like std::exchange template constexpr T qExchange(T &t, U &&newValue) noexcept(std::conjunction_v, std::is_nothrow_assignable>) { T old = std::move(t); t = std::forward(newValue); return old; } #endif // QT_NO_QEXCHANGE namespace QtPrivate { // helper to be used to trigger a "dependent static_assert(false)" // (for instance, in a final `else` branch of a `if constexpr`.) template struct type_dependent_false : std::false_type {}; template struct value_dependent_false : std::false_type {}; } namespace QTypeTraits { namespace detail { template && std::is_arithmetic_v && std::is_floating_point_v == std::is_floating_point_v && std::is_signed_v == std::is_signed_v && !std::is_same_v && !std::is_same_v && !std::is_same_v && !std::is_same_v>> struct Promoted { using type = decltype(T() + U()); }; } template using Promoted = typename detail::Promoted::type; /* 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 struct is_container : std::false_type {}; template struct is_container().begin() != std::declval().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 struct has_operator_equal : std::false_type {}; template struct has_operator_equal() == std::declval()))>> : std::true_type {}; QT_WARNING_POP // Two forward declarations template::value> struct expand_operator_equal_container; template struct expand_operator_equal_tuple; // the entry point for the public method template using expand_operator_equal = expand_operator_equal_container; // if T isn't a container check if it's a tuple like object template struct expand_operator_equal_container : expand_operator_equal_tuple {}; // if T::value_type exists, check first T::value_type, then T itself template struct expand_operator_equal_container : std::conjunction< std::disjunction< std::is_same, // avoid endless recursion expand_operator_equal >, expand_operator_equal_tuple> {}; // recursively check the template arguments of a tuple like object template using expand_operator_equal_recursive = std::conjunction...>; template struct expand_operator_equal_tuple : has_operator_equal {}; template struct expand_operator_equal_tuple> : expand_operator_equal_recursive {}; template struct expand_operator_equal_tuple> : expand_operator_equal_recursive {}; template struct expand_operator_equal_tuple> : expand_operator_equal_recursive {}; template struct expand_operator_equal_tuple> : expand_operator_equal_recursive {}; // the same for operator<(), see above for explanations template struct has_operator_less_than : std::false_type{}; template struct has_operator_less_than() < std::declval()))>> : std::true_type{}; template::value> struct expand_operator_less_than_container; template struct expand_operator_less_than_tuple; template using expand_operator_less_than = expand_operator_less_than_container; template struct expand_operator_less_than_container : expand_operator_less_than_tuple {}; template struct expand_operator_less_than_container : std::conjunction< std::disjunction< std::is_same, expand_operator_less_than >, expand_operator_less_than_tuple > {}; template using expand_operator_less_than_recursive = std::conjunction...>; template struct expand_operator_less_than_tuple : has_operator_less_than {}; template struct expand_operator_less_than_tuple> : expand_operator_less_than_recursive {}; template struct expand_operator_less_than_tuple> : expand_operator_less_than_recursive {}; template struct expand_operator_less_than_tuple> : expand_operator_less_than_recursive {}; template struct expand_operator_less_than_tuple> : expand_operator_less_than_recursive {}; } template struct is_dereferenceable : std::false_type {}; template struct is_dereferenceable().operator->())> > : std::true_type {}; template inline constexpr bool is_dereferenceable_v = is_dereferenceable::value; template struct has_operator_equal : detail::expand_operator_equal {}; template inline constexpr bool has_operator_equal_v = has_operator_equal::value; template using has_operator_equal_container = std::disjunction, QTypeTraits::has_operator_equal>; template struct has_operator_less_than : detail::expand_operator_less_than {}; template inline constexpr bool has_operator_less_than_v = has_operator_less_than::value; template using has_operator_less_than_container = std::disjunction, QTypeTraits::has_operator_less_than>; template using compare_eq_result = std::enable_if_t...>, bool>; template using compare_eq_result_container = std::enable_if_t...>, bool>; template using compare_lt_result = std::enable_if_t...>, bool>; template using compare_lt_result_container = std::enable_if_t...>, bool>; namespace detail { template const T &const_reference(); template T &reference(); } template struct has_ostream_operator : std::false_type {}; template struct has_ostream_operator() << detail::const_reference())>> : std::true_type {}; template inline constexpr bool has_ostream_operator_v = has_ostream_operator::value; template using has_ostream_operator_container = std::disjunction, QTypeTraits::has_ostream_operator>; template struct has_istream_operator : std::false_type {}; template struct has_istream_operator() >> detail::reference())>> : std::true_type {}; template inline constexpr bool has_istream_operator_v = has_istream_operator::value; template using has_istream_operator_container = std::disjunction, QTypeTraits::has_istream_operator>; template inline constexpr bool has_stream_operator_v = has_ostream_operator_v && has_istream_operator_v; } // namespace QTypeTraits QT_END_NAMESPACE #endif // QTTYPETRAITS_H