使用模板获取函数的参数类型
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...>>;
};
通过函数声明的另一种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>::type
是 char
;在这种情况下,您必须删除 -1
.
还请注意 std::remove_reference_t
。是必需的,因为您希望 param_type<foo, 3>::type
是 char
(无参考)而不是 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>, "!" );
}
假设我有一个具有以下签名的函数:
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...>>;
};
通过函数声明的另一种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>::type
是 char
;在这种情况下,您必须删除 -1
.
还请注意 std::remove_reference_t
。是必需的,因为您希望 param_type<foo, 3>::type
是 char
(无参考)而不是 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>, "!" );
}