#pragma once #include "util.hpp" #include "../type/type.hpp" namespace util { // // clang-format off namespace detail { template constexpr bool is_reference_wrapper_v = false; template constexpr bool is_reference_wrapper_v> = true; template constexpr decltype(auto) INVOKE(Type T::*f, T1 &&t1, Args &&... args) { if constexpr (type::is_member_function_pointer_v) { if constexpr (type::is_base_of_v>) return (util::forward(t1).*f)(util::forward(args)...); else if constexpr (is_reference_wrapper_v>) return (t1.get().*f)(util::forward(args)...); else return ((*util::forward(t1)).*f)(util::forward(args)...); } else { static_assert(type::is_member_object_pointer_v); static_assert(sizeof...(args) == 0); if constexpr (type::is_base_of_v>) return util::forward(t1).*f; else if constexpr (is_reference_wrapper_v>) return t1.get().*f; else return (*util::forward(t1)).*f; } } template constexpr decltype(auto) INVOKE(Fn &&f, Args &&... args) { return util::forward(f)(util::forward(args)...); } template constexpr T &FUN(T &t) noexcept { return t; } template void FUN(T &&) = delete; } // namespace detail template constexpr type::invoke_result_t invoke(Fn &&f, Args &&... args) noexcept(type::is_nothrow_invocable_v) { return detail::INVOKE(util::forward(f), util::forward(args)...); } template class reference_wrapper { public: // construct/copy/destroy template (util::declval()), type::enable_if_t>>())> constexpr reference_wrapper(U &&u) noexcept(noexcept(detail::FUN(util::forward(u)))) : _ptr(util::addressof(detail::FUN(util::forward(u)))) {} reference_wrapper(const reference_wrapper &) noexcept = default; // assignment reference_wrapper &operator=(const reference_wrapper &) noexcept = default; // access constexpr operator T &() const noexcept { return *_ptr; } constexpr T &get() const noexcept { return *_ptr; } template constexpr type::invoke_result_t operator()(ArgTypes &&... args) const { return invoke(get(), util::forward(args)...); } // types using type = T; private: T *_ptr; }; // deduction guides template reference_wrapper(T &) -> reference_wrapper; // clang-format on } // namespace util