diff options
Diffstat (limited to 'src/corelib/kernel/qobjectdefs_impl.h')
-rw-r--r-- | src/corelib/kernel/qobjectdefs_impl.h | 77 |
1 files changed, 27 insertions, 50 deletions
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h index aed50d6c5a..0624dd2584 100644 --- a/src/corelib/kernel/qobjectdefs_impl.h +++ b/src/corelib/kernel/qobjectdefs_impl.h @@ -257,55 +257,32 @@ namespace QtPrivate { } }; - /* - Logic that checks if the underlying type of an enum is signed or not. - Needs an external, explicit check that E is indeed an enum. Works - around the fact that it's undefined behavior to instantiate - std::underlying_type on non-enums (cf. §20.13.7.6 [meta.trans.other]). - */ - template<typename E, typename Enable = void> - struct IsEnumUnderlyingTypeSigned : std::false_type - { - }; - - template<typename E> - struct IsEnumUnderlyingTypeSigned<E, typename std::enable_if<std::is_enum<E>::value>::type> - : std::integral_constant<bool, std::is_signed<typename std::underlying_type<E>::type>::value> - { - }; - - /* - Logic that checks if the argument of the slot does not narrow the - argument of the signal when used in list initialization. Cf. §8.5.4.7 - [dcl.init.list] for the definition of narrowing. - For incomplete From/To types, there's no narrowing. - */ - template<typename From, typename To, typename Enable = void> - struct AreArgumentsNarrowedBase : std::false_type - { - }; - + // Traits to detect if there is a conversion between two types, + // and that conversion does not include a narrowing conversion. template <typename T> - using is_bool = std::is_same<bool, typename std::decay<T>::type>; - - template<typename From, typename To> - struct AreArgumentsNarrowedBase<From, To, typename std::enable_if<sizeof(From) && sizeof(To)>::type> - : std::integral_constant<bool, - (std::is_floating_point<From>::value && std::is_integral<To>::value) || - (std::is_floating_point<From>::value && std::is_floating_point<To>::value && sizeof(From) > sizeof(To)) || - ((std::is_pointer<From>::value || std::is_member_pointer<From>::value) && QtPrivate::is_bool<To>::value) || - ((std::is_integral<From>::value || std::is_enum<From>::value) && std::is_floating_point<To>::value) || - (std::is_integral<From>::value && std::is_integral<To>::value - && (sizeof(From) > sizeof(To) - || (std::is_signed<From>::value ? !std::is_signed<To>::value - : (std::is_signed<To>::value && sizeof(From) == sizeof(To))))) || - (std::is_enum<From>::value && std::is_integral<To>::value - && (sizeof(From) > sizeof(To) - || (IsEnumUnderlyingTypeSigned<From>::value ? !std::is_signed<To>::value - : (std::is_signed<To>::value && sizeof(From) == sizeof(To))))) - > - { - }; + struct NarrowingDetector { T t[1]; }; // from P0608 + + template <typename From, typename To, typename Enable = void> + struct IsConvertibleWithoutNarrowing : std::false_type {}; + + template <typename From, typename To> + struct IsConvertibleWithoutNarrowing<From, To, + std::void_t< decltype( NarrowingDetector<To>{ {std::declval<From>()} } ) > + > : std::true_type {}; + + // Check for the actual arguments. If they are exactly the same, + // then don't bother checking for narrowing; as a by-product, + // this solves the problem of incomplete types (which must be supported, + // or they would error out in the trait above). + template <typename From, typename To, typename Enable = void> + struct AreArgumentsConvertibleWithoutNarrowingBase : std::false_type {}; + + template <typename From, typename To> + struct AreArgumentsConvertibleWithoutNarrowingBase<From, To, + std::enable_if_t< + std::disjunction_v<std::is_same<From, To>, IsConvertibleWithoutNarrowing<From, To>> + > + > : std::true_type {}; /* Logic that check if the arguments of the slot matches the argument of the signal. @@ -318,8 +295,8 @@ namespace QtPrivate { static const typename RemoveRef<A1>::Type &dummy(); enum { value = sizeof(test(dummy())) == sizeof(int) }; #ifdef QT_NO_NARROWING_CONVERSIONS_IN_CONNECT - using AreArgumentsNarrowed = AreArgumentsNarrowedBase<typename RemoveRef<A1>::Type, typename RemoveRef<A2>::Type>; - Q_STATIC_ASSERT_X(!AreArgumentsNarrowed::value, "Signal and slot arguments are not compatible (narrowing)"); + using AreArgumentsConvertibleWithoutNarrowing = AreArgumentsConvertibleWithoutNarrowingBase<std::decay_t<A1>, std::decay_t<A2>>; + Q_STATIC_ASSERT_X(AreArgumentsConvertibleWithoutNarrowing::value, "Signal and slot arguments are not compatible (narrowing)"); #endif }; template<typename A1, typename A2> struct AreArgumentsCompatible<A1, A2&> { enum { value = false }; }; |