ADC/common/adc_traits.h
2024-01-22 00:34:49 +03:00

98 lines
2.4 KiB
C++

#pragma once
#include <ranges>
#include <tuple>
#include <type_traits>
#include <format>
/*
ABSTRACT DEVICE COMPONENTS LIBRARY
*/
namespace adc::traits
{
// check if type can be used with std::format_to
// (from https://stackoverflow.com/questions/72430369/how-to-check-that-a-type-is-formattable-using-type-traits-concepts)
template<typename T>
concept formattable = requires (T& v, std::format_context ctx) {
std::formatter<std::remove_cvref_t<T>>().format(v, ctx);
};
// range of char/const char
template <typename R, typename CharT = char>
concept adc_char_range = std::ranges::range<R> && std::is_same_v<std::remove_cv_t<std::ranges::range_value_t<R>>, CharT>;
// deduce returned type of callable
template <typename T>
using adc_retval_t = std::invoke_result_t<std::remove_cvref_t<T>>;
// helper classes
template <typename... Ts>
struct adc_func_traits_helper_t;
template <typename R>
struct adc_func_traits_helper_t<R> {
using ret_t = R;
using args_t = std::tuple<>;
using arg1_t = void;
};
template <typename R, typename Arg, typename... Args>
struct adc_func_traits_helper_t<R, Arg, Args...> {
using ret_t = R;
using args_t = std::tuple<Arg, Args...>;
using arg1_t = Arg;
};
// callable traits
template <typename F>
struct adc_func_traits;
template <typename R, typename... Args>
struct adc_func_traits<R (*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename R, typename... Args>
struct adc_func_traits<R(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename C, typename R, typename... Args>
struct adc_func_traits<R (C::*)(Args...)> : adc_func_traits_helper_t<R, Args...> {
};
template <typename C, typename R, typename... Args>
struct adc_func_traits<R (C::*)(Args...) const> : adc_func_traits_helper_t<R, Args...> {
};
template <typename F>
struct adc_func_traits : adc_func_traits<decltype(&F::operator())> {
};
// deduce type
template <typename T>
using adc_deduced_type =
std::conditional_t<std::is_lvalue_reference_v<T> && !std::is_const_v<std::remove_reference_t<T>>,
T,
std::remove_cvref_t<T>>;
// perfect-forwarding wrapper
template <typename T, typename... Ts>
constexpr static auto adc_pf_wrapper(T&& v, Ts&&... vs)
{
return std::tuple<adc_deduced_type<T>, adc_deduced_type<Ts>...>(std::forward<T>(v), std::forward<Ts>(vs)...);
}
} // namespace adc::traits