101 lines
3.4 KiB
C++
101 lines
3.4 KiB
C++
#pragma once
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
|
|
namespace kpn {
|
|
|
|
// ── Primary template — not defined; only specialisations match ────────────────
|
|
template<typename F>
|
|
struct function_traits;
|
|
|
|
// Free function
|
|
template<typename R, typename... Args>
|
|
struct function_traits<R(Args...)> {
|
|
using return_t = R;
|
|
using args = std::tuple<Args...>;
|
|
static constexpr std::size_t arity = sizeof...(Args);
|
|
};
|
|
|
|
// Function pointer
|
|
template<typename R, typename... Args>
|
|
struct function_traits<R(*)(Args...)> : function_traits<R(Args...)> {};
|
|
|
|
// Member function pointer (const)
|
|
template<typename C, typename R, typename... Args>
|
|
struct function_traits<R(C::*)(Args...) const> : function_traits<R(Args...)> {};
|
|
|
|
// Member function pointer (non-const)
|
|
template<typename C, typename R, typename... Args>
|
|
struct function_traits<R(C::*)(Args...)> : function_traits<R(Args...)> {};
|
|
|
|
// Callable (lambda / std::function) — delegate to operator()
|
|
template<typename F>
|
|
struct function_traits : function_traits<decltype(&F::operator())> {};
|
|
|
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
|
|
template<typename F>
|
|
using return_t = typename function_traits<std::remove_cvref_t<F>>::return_t;
|
|
|
|
template<typename F>
|
|
using args_t = typename function_traits<std::remove_cvref_t<F>>::args;
|
|
|
|
template<typename F>
|
|
inline constexpr std::size_t arity_v = function_traits<std::remove_cvref_t<F>>::arity;
|
|
|
|
// ── Tuple detection ───────────────────────────────────────────────────────────
|
|
|
|
template<typename T>
|
|
struct is_tuple : std::false_type {};
|
|
|
|
template<typename... Ts>
|
|
struct is_tuple<std::tuple<Ts...>> : std::true_type {};
|
|
|
|
template<typename T>
|
|
inline constexpr bool is_tuple_v = is_tuple<T>::value;
|
|
|
|
// ── Normalise return type to always be a tuple ────────────────────────────────
|
|
// void → std::tuple<>
|
|
// T (non-tup) → std::tuple<T>
|
|
// tuple<...> → tuple<...> (unchanged)
|
|
|
|
template<typename T>
|
|
struct normalise_return {
|
|
using type = std::tuple<T>;
|
|
};
|
|
|
|
template<>
|
|
struct normalise_return<void> {
|
|
using type = std::tuple<>;
|
|
};
|
|
|
|
template<typename... Ts>
|
|
struct normalise_return<std::tuple<Ts...>> {
|
|
using type = std::tuple<Ts...>;
|
|
};
|
|
|
|
template<typename T>
|
|
using normalised_return_t = typename normalise_return<T>::type;
|
|
|
|
// ── Output count from a function type ────────────────────────────────────────
|
|
|
|
template<typename F>
|
|
inline constexpr std::size_t output_count_v =
|
|
std::tuple_size_v<normalised_return_t<return_t<F>>>;
|
|
|
|
// ── repeat_tuple: std::tuple<T, T, ..., T> with N repetitions ────────────────
|
|
|
|
template<typename T, std::size_t N, typename Seq = std::make_index_sequence<N>>
|
|
struct repeat_tuple;
|
|
|
|
template<typename T, std::size_t N, std::size_t... Is>
|
|
struct repeat_tuple<T, N, std::index_sequence<Is...>> {
|
|
template<std::size_t> using always_T = T;
|
|
using type = std::tuple<always_T<Is>...>;
|
|
};
|
|
|
|
template<typename T, std::size_t N>
|
|
using repeat_tuple_t = typename repeat_tuple<T, N>::type;
|
|
|
|
} // namespace kpn
|