c++ - 如何编写可以使用函数的参数类型推断类型的模板?
问题描述
如何编写一个使用函数作为模板参数的模板,并通过该函数的参数类型自动推断出其他类型名?
void foo(int *p) {}
template<typename T, void (*F)(T*)>
struct bar
{
bar(T* t)
{
F(t);
}
}
int *p;
bar<int, foo> b(p); // both int and foo are required here
如何编写支持仅用foo
作参数的模板
bar<foo> b(p);
解决方案
如果您可以将 c++17 与它的自动模板参数一起使用(如评论中的@nm 所说),您可以将其用作模板参数,然后使用具有类型特征的类型 T。
首先,我们需要标准类型特征和类型特征来获取一元函数(你的 foo)的参数,我们可以这样写:
#include <type_traits>
// Trait to get the argument type of a unary function
template<typename T>
struct unary_func_arg;
template<typename R, typename T>
struct unary_func_arg< R(*)(T) >
{
using type = T;
};
如果您将函数指针以外的任何内容放入其中,这将产生错误,因为未声明主要特化。
在此之后,我们终于可以这样写 bar:
template< auto F >
struct bar
{
// Assert it's a function pointer
static_assert( std::is_pointer_v<decltype(F)> );
static_assert( std::is_function_v< std::remove_pointer_t<decltype(F)> > );
// Get the parameter type
using T = typename unary_func_arg< decltype(F) >::type;
bar(T t)
{
F(t);
}
};
我们必须确保 F 是一个函数指针,所以我们静态断言它,然后我们从我们的类型特征中获取类型 T。
现在你可以像这样声明 f 和 b :
int* p;
bar<foo> b(p);
编辑:如果您需要 T 不是指针以便您可以编写 T*,您可以创建一个删除 1 个指针级别的类型特征,或者将此处的类型特征修改为:
// Trait to get the argument type of a unary function
template<typename T>
struct unary_func_arg_pointer;
template<typename R, typename T>
struct unary_func_arg_pointer< R(*)(T*) >
{
using type = T;
};
现在 T 在这个例子中只是 int