#pragma once #include #include #include #include /* 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 concept formattable = requires (T& v, std::format_context ctx) { std::formatter>().format(v, ctx); }; // range of char/const char template concept adc_char_range = std::ranges::range && std::is_same_v>, CharT>; // deduce returned type of callable template using adc_retval_t = std::invoke_result_t>; // helper classes template struct adc_func_traits_helper_t; template struct adc_func_traits_helper_t { using ret_t = R; using args_t = std::tuple<>; using arg1_t = void; }; template struct adc_func_traits_helper_t { using ret_t = R; using args_t = std::tuple; using arg1_t = Arg; }; // callable traits template struct adc_func_traits; template struct adc_func_traits : adc_func_traits_helper_t { }; template struct adc_func_traits : adc_func_traits_helper_t { }; template struct adc_func_traits : adc_func_traits_helper_t { }; template struct adc_func_traits : adc_func_traits_helper_t { }; template struct adc_func_traits : adc_func_traits { }; // deduce type template using adc_deduced_type = std::conditional_t && !std::is_const_v>, T, std::remove_cvref_t>; // perfect-forwarding wrapper template constexpr static auto adc_pf_wrapper(T&& v, Ts&&... vs) { return std::tuple, adc_deduced_type...>(std::forward(v), std::forward(vs)...); } } // namespace adc::traits