使用模板获取函数的参数类型

Getting parameter type of function with templates

假设我有一个具有以下签名的函数:

void foo(std::string const& a, int b, char &c) {
    ...
}

我怎样才能做类似 param_type<foo, 3>::type 的事情来获取 type == char?

背景:

我有一组 macros/TMP,它生成一个结构,用于将 json 对象转换为 C++ 值。我还有一组代表每个 json 类型(基元、数组、对象等)的结构。主结构由 X 宏定义,实现者必须将参数类型(也用作字段类型)、json 类型(结构之一)和键名传递到 X 宏中定义字段。

我希望能够将字段类型与参数类型分开,因此我可以将类似 std::optional<TField> 的内容作为结构的字段类型,并将 TField 传递给解析方法。这些宏在很多地方都在使用,所以我不想在 X 宏中添加另一个参数。

我尝试使用 auto 变量,但据我所知,像下面这样的东西是不可能的,这就是为什么我想要 param_type.

auto value;
parse(..., value);
field = value;

在这种情况下

您可以检查2个类型是否与std::is_same<T,U>::value相同
if (std::is_same<param_type<foo, 3>::type,char>::value) {
    /*stuff*/
}else {
    /*stuff2*/
}

查看更多关于 is_same

您可以创建具有偏特化的函数特征:

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

通过函数声明的另一种std::tuple_element方式(仅声明,不需要定义)

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

所以param_type就变成了

template <auto X, std::size_t Ind>
struct param_type
 { using type = decltype( pt_helper<Ind>(X) ); };

观察 pt_helper 声明中的 Ind-1u:您要求 param_type return 带有参数 3 的函数的第三个参数类型:通常, 在 C/C++ 世界中,索引从零开始计数。我建议你接受 param_type<foo, 2>::typechar;在这种情况下,您必须删除 -1.

还请注意 std::remove_reference_t。是必需的,因为您希望 param_type<foo, 3>::typechar(无参考)而不是 char &(有参考)。

总之,下面是一个完整的编译示例

#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>, "!" );
 }