#pragma once #include #include #include "is_reference_wrapper.hpp" template struct invoke_impl { template static constexpr auto call(F&& f, Args&&... args) noexcept(noexcept(static_cast(f)(static_cast(args)...))) -> decltype(static_cast(f)(static_cast(args)...)) { return static_cast(f)(static_cast(args)...); } }; template struct invoke_impl { template>> > static constexpr auto get(T&& t) noexcept -> T&& { return static_cast(t); } template>> > static constexpr auto get(T&& t) noexcept -> decltype(t.get()) { return t.get(); } template>>, class = std::enable_if_t>> > static constexpr auto get(T&& t) noexcept(noexcept(*static_cast(t))) -> decltype(*static_cast(t)) { return *static_cast(t); } template> > static constexpr auto call(AA B::*pmf, T&& t, Args&&... args) noexcept(noexcept(((get)(static_cast(t)).*pmf)(static_cast(args)...))) -> decltype(((get)(static_cast(t)).*pmf)(static_cast(args)...)) { return ((get)(static_cast(t)).*pmf)(static_cast(args)...); } template static constexpr auto call(A B::*pmd, T&& t) noexcept(noexcept((get)(static_cast(t)).*pmd)) -> decltype((get)(static_cast(t)).*pmd) { return (get)(static_cast(t)).*pmd; } }; template constexpr auto invoke(F&& f, Args&&... args) noexcept(noexcept(invoke_impl>::call( static_cast(f), static_cast(args)...))) -> decltype(invoke_impl>::call( static_cast(f), static_cast(args)...)) { return invoke_impl>::call( static_cast(f), static_cast(args)...); } template>::call( std::declval(), std::declval()...)), class = std::enable_if_t || std::is_convertible_v> > constexpr R invoke(F&& f, Args&&... args) noexcept(noexcept(invoke_impl>::call( static_cast(f), static_cast(args)...)) && (std::is_void_v || std::is_nothrow_convertible_v)) { if constexpr (!std::is_void_v) return invoke_impl>::call( static_cast(f), static_cast(args)...); else invoke_impl>::call( static_cast(f), static_cast(args)...); }