首页 > 解决方案 > 如何编写可以使用函数的参数类型推断类型的模板?

问题描述

如何编写一个使用函数作为模板参数的模板,并通过该函数的参数类型自动推断出其他类型名?

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++templates

解决方案


如果您可以将 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


推荐阅读