Home > Enterprise >  Getting parameter type of function with templates
Getting parameter type of function with templates

Time:01-07

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...>>;
};

Demo

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

  •  Tags:  
  • Related