#pragma once #include #include #include #include "is_reference_wrapper.hpp" #include "invoke.hpp" template, bool = std::is_bind_expression_v, bool = ((std::is_placeholder_v) > 0)> struct BoundArgument { static constexpr int position { 0 }; template using type = TDi&; template using const_type = TDi const&; }; template struct BoundArgument { static constexpr int position { 0 }; template using type = typename TDi::type&; template using const_type = typename TDi::type&; }; template struct BoundArgument { static constexpr int position { 0 }; template using type = std::invoke_result_t; template using const_type = std::invoke_result_t; }; template struct BoundArgument { static constexpr int position { std::is_placeholder_v }; template using type = std::tuple_element_t>; template using const_type = std::tuple_element_t>; }; template struct Bind { FD fd; std::tuple bound_args; private: template static constexpr decltype(auto) transform_args(cvTDi& tdi, U&&... u) { using TDi = std::remove_cvref_t; if constexpr (is_reference_wrapper_v) return tdi.get(); else if constexpr (std::is_bind_expression_v) return tdi(std::forward(u)...); else if constexpr ((std::is_placeholder_v) > 0) { constexpr std::size_t position = std::is_placeholder_v; return std::get(std::forward_as_tuple(std::forward(u)...)); } else return tdi; } template static constexpr decltype(auto) call(cvFD& fd, /* cv std::tuple& */ BoundArgTpl& bound_args, std::index_sequence, UnBoundArgs&&... unbound_args ) { if constexpr (std::is_same_v) return (invoke)(fd, transform_args(std::get(bound_args), std::forward(unbound_args)...)...); else return (invoke)(fd, transform_args(std::get(bound_args), std::forward(unbound_args)...)...); } public: template constexpr decltype(auto) operator()(UnBoundArgs&&... unbound_args) { static_assert( std::is_invocable_v< FD&, typename BoundArgument::template type... >, "The target object is not callable with the given arguments." ); return (call)(fd, bound_args, std::index_sequence_for{}, std::forward(unbound_args)...); } template constexpr decltype(auto) operator()(UnBoundArgs&&... unbound_args) const { static_assert( std::is_invocable_v< FD const&, typename BoundArgument::template const_type... >, "The target object is not callable with the given arguments." ); return (call)(fd, bound_args, std::index_sequence_for{}, std::forward(unbound_args)...); } }; namespace std { template struct is_bind_expression> : true_type {}; template struct is_bind_expression> : true_type {}; } template constexpr Bind, void(void), std::decay_t...> bind(F&& f, BoundArgs&&... bound_args) { return { std::forward(f), { std::forward(bound_args)... } }; } template constexpr Bind, R, std::decay_t...> bind(F&& f, BoundArgs&&... bound_args) { return { std::forward(f), { std::forward(bound_args)... } }; }