// Copyright (C) 2021 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 QNATIVEINTERFACE_H #define QNATIVEINTERFACE_H #include QT_BEGIN_NAMESPACE // We declare a virtual non-inline function in the form // of the destructor, making it the key function. This // ensures that the typeinfo of the class is exported. // By being protected, we also ensure that pointers to // the interface can't be deleted. #define QT_DECLARE_NATIVE_INTERFACE_3(NativeInterface, Revision, BaseType) \ protected: \ virtual ~NativeInterface(); \ \ struct TypeInfo { \ using baseType = BaseType; \ static constexpr char const *name = QT_STRINGIFY(NativeInterface); \ static constexpr int revision = Revision; \ }; \ \ template \ friend struct QNativeInterface::Private::has_type_info; \ \ template \ friend bool constexpr QNativeInterface::Private::hasTypeInfo(); \ \ template \ friend struct QNativeInterface::Private::TypeInfo; \ public: \ NativeInterface() = default; \ Q_DISABLE_COPY_MOVE(NativeInterface) // Revisioned interfaces only make sense when exposed through a base // type via QT_DECLARE_NATIVE_INTERFACE_ACCESSOR, as the revision // checks happen at that level (and not for normal dynamic_casts). #define QT_DECLARE_NATIVE_INTERFACE_2(NativeInterface, Revision) \ static_assert(false, "Must provide a base type when specifying revision"); #define QT_DECLARE_NATIVE_INTERFACE_1(NativeInterface) \ QT_DECLARE_NATIVE_INTERFACE_3(NativeInterface, 0, void) #define QT_DECLARE_NATIVE_INTERFACE(...) \ QT_OVERLOADED_MACRO(QT_DECLARE_NATIVE_INTERFACE, __VA_ARGS__) namespace QNativeInterface::Private { // Basic type-trait to verify that a given native interface has // all the required type information for us to evaluate it. template struct has_type_info : std::false_type {}; // The type-trait is friended by TypeInfo, so that we can // evaluate TypeInfo in the template arguments. template struct has_type_info> : std::true_type {}; // We need to wrap the instantiation of has_type_info in a // function friended by TypeInfo, otherwise MSVC will not // let us evaluate TypeInfo in the template arguments. template bool constexpr hasTypeInfo() { return has_type_info::value; } template struct TypeInfo { // To ensure SFINAE works for hasTypeInfo we can't use it in a constexpr // variable that also includes an expression that relies on the type // info. This helper variable is okey, as it it self contained. static constexpr bool haveTypeInfo = hasTypeInfo(); // We can then use the helper variable in a constexpr condition in a // function, which does not break SFINAE if haveTypeInfo is false. template static constexpr bool isCompatibleHelper() { if constexpr (haveTypeInfo) return std::is_base_of::value; else return false; } // MSVC however doesn't like constexpr functions in enable_if_t conditions, // so we need to wrap it yet again in a constexpr variable. This is fine, // as all the SFINAE magic has been resolved at this point. template static constexpr bool isCompatibleWith = isCompatibleHelper(); // The revision and name accessors are not used in enable_if_t conditions, // so we can leave them as constexpr functions. As this class template is // friended by TypeInfo we can access the protected members of TypeInfo. static constexpr int revision() { if constexpr (haveTypeInfo) return NativeInterface::TypeInfo::revision; else return 0; } static constexpr char const *name() { if constexpr (haveTypeInfo) return NativeInterface::TypeInfo::name; else return nullptr; } }; // Wrapper type to make the error message in case // of incompatible interface types read better. template struct NativeInterface : TypeInfo {}; } // QNativeInterface::Private // Declares an accessor for the native interface #ifdef Q_QDOC #define QT_DECLARE_NATIVE_INTERFACE_ACCESSOR(T) \ template \ QNativeInterface *nativeInterface() const; #else #define QT_DECLARE_NATIVE_INTERFACE_ACCESSOR(T) \ template , \ typename BaseType = T, std::enable_if_t, bool> = true> \ NativeInterface *nativeInterface() const \ { \ return static_cast(resolveInterface( \ TypeInfo::name(), TypeInfo::revision())); \ } \ protected: \ void *resolveInterface(const char *name, int revision) const; \ public: #endif QT_END_NAMESPACE #endif // QNATIVEINTERFACE_H