Files
Cpp-in-Embedded-Systems/Chapter17/cib/libs/stdx/function_traits.hpp
Amar Mahmutbegovic 526e6ec009 rename chapters
2025-02-09 13:11:21 +01:00

86 lines
2.8 KiB
C++

#pragma once
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/utility.hpp>
#include <functional>
#include <type_traits>
#include <utility>
namespace stdx {
inline namespace v1 {
namespace detail {
template <typename...> struct function_traits;
template <typename R, typename... Args>
struct function_traits<std::function<R(Args...)>> {
using return_type = R;
template <template <typename...> typename List> using args = List<Args...>;
template <template <typename...> typename List>
using decayed_args = List<std::decay_t<Args>...>;
using arity = std::integral_constant<std::size_t, sizeof...(Args)>;
template <auto N>
using nth_arg = boost::mp11::mp_at_c<args<boost::mp11::mp_list>, N>;
template <auto N>
using decayed_nth_arg =
boost::mp11::mp_at_c<decayed_args<boost::mp11::mp_list>, N>;
};
} // namespace detail
template <typename F>
using function_traits =
detail::function_traits<decltype(std::function{std::declval<F>()})>;
template <typename F> using return_t = typename function_traits<F>::return_type;
template <typename F, template <typename...> typename List>
using args_t = typename function_traits<F>::template args<List>;
template <typename F, template <typename...> typename List>
using decayed_args_t = typename function_traits<F>::template decayed_args<List>;
template <typename F>
using nongeneric_arity_t = typename function_traits<F>::arity;
template <typename F, auto N>
using nth_arg_t = typename function_traits<F>::template nth_arg<N>;
template <typename F, auto N>
using decayed_nth_arg_t =
typename function_traits<F>::template decayed_nth_arg<N>;
namespace detail {
template <auto> struct any_type {
// NOLINTNEXTLINE(google-explicit-constructor)
template <typename T> operator T();
};
template <typename F, std::size_t... Is>
constexpr auto try_invoke_impl(std::index_sequence<Is...>)
-> std::invoke_result_t<F, any_type<Is>...>;
template <typename F, typename N>
using try_invoke =
decltype(try_invoke_impl<F>(std::make_index_sequence<N::value>{}));
template <typename F, typename N>
using has_arg_count = boost::mp11::mp_valid<try_invoke, F, N>;
template <typename F, typename N> struct generic_arity;
template <typename F, typename N>
using generic_arity_t = typename generic_arity<F, N>::type;
template <typename F, typename N> struct generic_arity {
using type = boost::mp11::mp_eval_if<
has_arg_count<F, N>, N, generic_arity_t, F,
std::integral_constant<std::size_t, N::value + 1u>>;
};
} // namespace detail
template <typename F>
using arity_t = boost::mp11::mp_eval_or<
detail::generic_arity_t<F, std::integral_constant<std::size_t, 0u>>,
nongeneric_arity_t, F>;
template <typename F> constexpr auto arity_v = arity_t<F>::value;
} // namespace v1
} // namespace stdx