// 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 QXPFUNCTIONAL_H #define QXPFUNCTIONAL_H #include // // W A R N I N G // ------------- // // This file is not part of the Qt API. Types and functions defined in this // file can reliably be replaced by their std counterparts, once available. // You may use these definitions in your own code, but be aware that we // will remove them once Qt depends on the C++ version that supports // them in namespace std. There will be NO deprecation warning, the // definitions will JUST go away. // // If you can't agree to these terms, don't use these definitions! // // We mean it. // #include #include #include QT_BEGIN_NAMESPACE namespace qxp { // like P0792r9's function_ref: // [func.wrap.ref], non-owning wrapper template class function_ref; // not defined // template // class function_ref; // see below // // [func.wrap.ref.general] // The header provides partial specializations of function_ref for each combination // of the possible replacements of the placeholders cv and noex where: // - cv is either const or empty. // - noex is either true or false. namespace detail { template using if_function = std::enable_if_t, bool>; template using if_non_function = std::enable_if_t, bool>; template using copy_const_t = std::conditional_t< std::is_const_v, std::add_const_t, To >; template union BoundEntityType { template = true> explicit constexpr BoundEntityType(F *f) : fun(reinterpret_cast(f)) {} template = true> explicit constexpr BoundEntityType(T *t) : obj(static_cast(t)) {} Const *obj; QFunctionPointer fun; }; template class function_ref_base { protected: ~function_ref_base() = default; using BoundEntityType = detail::BoundEntityType; template using is_invocable_using = std::conditional_t< noex, std::is_nothrow_invocable_r, std::is_invocable_r >; using ThunkPtr = R(*)(BoundEntityType, ArgTypes&&...) noexcept(noex); BoundEntityType m_bound_entity; ThunkPtr m_thunk_ptr; public: template< class F, std::enable_if_t, is_invocable_using >, bool> = true > Q_IMPLICIT function_ref_base(F* f) noexcept : m_bound_entity(f), m_thunk_ptr([](BoundEntityType ctx, ArgTypes&&... args) noexcept(noex) -> R { return q23::invoke_r(reinterpret_cast(ctx.fun), std::forward(args)...); }) {} template< class F, std::enable_if_t, function_ref_base>>, #ifdef Q_OS_VXWORKS // The VxWorks compiler is trying to match this ctor against // qxp::function_ref in lieu of using the copy-constructor, so ban // matching against the equivalent qxp::function_ref here. // This doesn't change anything on other platforms, so to save // on compile-speed, enable it only for VxWorks: std::negation< std::is_same< q20::remove_cvref_t, std::conditional_t< std::is_const_v, qxp::function_ref, qxp::function_ref > > >, #endif // Q_OS_VXWORKS std::negation>>, is_invocable_using>&> >, bool> = true > Q_IMPLICIT constexpr function_ref_base(F&& f) noexcept : m_bound_entity(std::addressof(f)), m_thunk_ptr([](BoundEntityType ctx, ArgTypes&&... args) noexcept(noex) -> R { using That = copy_const_t>; return q23::invoke_r(*static_cast(ctx.obj), std::forward(args)...); }) {} protected: template < class T, std::enable_if_t, std::is_pointer > >, bool> = true > function_ref_base& operator=(T) = delete; // Invocation [func.wrap.ref.inv] R operator()(ArgTypes... args) const noexcept(noex) { return m_thunk_ptr(m_bound_entity, std::forward(args)...); } }; } // namespace detail #define QT_SPECIALIZE_FUNCTION_REF(cv, noex) \ template \ class function_ref \ : private detail::function_ref_base< noex , cv void, R, ArgTypes...> \ { \ using base = detail::function_ref_base< noex , cv void, R, ArgTypes...>; \ \ public: \ using base::base; \ using base::operator(); \ } \ /* end */ QT_SPECIALIZE_FUNCTION_REF( , false); QT_SPECIALIZE_FUNCTION_REF(const, false); QT_SPECIALIZE_FUNCTION_REF( , true ); QT_SPECIALIZE_FUNCTION_REF(const, true ); #undef QT_SPECIALIZE_FUNCTION_REF // deduction guides [func.wrap.ref.deduct] template < class F, detail::if_function = true > function_ref(F*) -> function_ref; } // namespace qxp QT_END_NAMESPACE #endif /* QXPFUNCTIONAL_H */