Let's say I have a function with the following signature:
void foo(std::string const& a, int b, char &c) {
...
}
How could I do something like param_type<foo, 3>::type to get type == char?
Background:
I have a set of macros/TMP which generates a struct for converting a json object into a c value. I also have a set of structs representing each of the json types (primitives, array, object, etc). The main struct is defined by an X-macro, and the implementer must pass the parameter type (also used as the field type), the json type (one of the structs), and the key name into the X macros to define the fields.
I want to be able to separate the field type from the parameter type, so I can have something like std::optional<TField> as the struct's field type and TField passed to the parse method. These macros are being used in many places, so I don't want to add another parameter to the X macros.
I tried using an auto variable but as far as I know, something like the following isn't possible, which is why I want param_type.
auto value;
parse(..., value);
field = value;
CodePudding user response:
You can create a function traits with partial specialization:
template <auto func, std::size_t I>
struct param_type;
template <typename Ret, typename... Args, Ret (*func)(Args...), std::size_t I>
struct param_type<func, I>
{
using type = std::tuple_element_t<I, std::tuple<Args...>>;
};
// C-ellipsis version aka printf-like functions
template <typename Ret, typename... Args, Ret (*func)(Args..., ...), std::size_t I>
struct param_type<func, I>
{
using type = std::tuple_element_t<I, std::tuple<Args...>>;
};
CodePudding user response:
Another std::tuple_element way pass through a function declaration (only declaration, no definition required)
template <std::size_t Ind, typename R, typename ... Args>
std::tuple_element_t<Ind-1u, std::tuple<std::remove_reference_t<Args>...>>
pt_helper (R(Args...));
so param_type simply become
template <auto X, std::size_t Ind>
struct param_type
{ using type = decltype( pt_helper<Ind>(X) ); };
Observe the Ind-1u in the pt_helper declaration: you asked that param_type return the third argument type of the function with argument 3: usually, in C/C world, the index are counted from zero. I suggest that you accept that param_type<foo, 2>::type is char; in that case you have to remove the -1.
Observe also the std::remove_reference_t. Is required because you want that param_type<foo, 3>::type is char (without reference) and not char & (with reference).
Anyway, the following is a full compiling example
#include <tuple>
#include <string>
#include <type_traits>
void foo (std::string const& a, int b, char &c)
{ }
template <std::size_t Ind, typename R, typename ... Args>
std::tuple_element_t<Ind-1u, std::tuple<std::remove_reference_t<Args>...>>
pt_helper (R(Args...));
template <auto X, std::size_t Ind>
struct param_type
{ using type = decltype( pt_helper<Ind>(X) ); };
int main ()
{
using T = typename param_type<foo, 3u>::type;
static_assert( std::is_same_v<T, char>, "!" );
}
CodePudding user response:
You can check if 2 types are the same with std::is_same<T,U>::value in this case
if (std::is_same<param_type<foo, 3>::type,char>::value) {
/*stuff*/
}else {
/*stuff2*/
}
See more about is_same
