Search code examples
c++template-meta-programming

Getting parameter type of function with templates


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;

Solution

  • 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