C++ 如何使用函数'编写可以推断类型的模板;什么是参数类型?

C++ 如何使用函数'编写可以推断类型的模板;什么是参数类型?,c++,templates,C++,Templates,如何编写一个使用函数作为模板参数的模板,并根据该函数的参数类型自动推断出其他类型的名称 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 如果您可以将c++17与它的

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

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

如果您可以将c++17与它的自动模板参数(如@n.m.在评论中所说)一起使用,那么您可以将其用作模板参数,然后将类型T与类型traits一起使用

首先,我们需要标准类型特征和类型特征来获取一元函数(您的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;
};
int* p;
bar<foo> b(p);
#包括
//Trait获取一元函数的参数类型
模板
结构一元函数参数;
模板
结构一元函数参数
{
使用类型=T;
};
如果将函数指针以外的任何东西放入其中,则会产生错误,因为未声明主专门化

在此之后,我们终于可以这样写:

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);
    }
};
模板
结构条
{
//断言它是一个函数指针
静态_断言(std::is_pointer_v);
静态断言(std::is_function_v);
//获取参数类型
使用T=typename一元函数参数::type;
巴(T)
{
F(t);
}
};
我们必须确保F是一个函数指针,所以我们静态断言它,然后从类型trait中得到类型T

现在您可以这样声明f和b:

#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;
};
int* p;
bar<foo> b(p);
int*p;
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;
};
//获取一元函数的参数类型的Trait
模板
结构一元函数参数指针;
模板
结构一元函数参数指针
{
使用类型=T;
};

现在,在本例中,T仅为int,在C++11中,类无法推断所传递函数的所有类型。但函数可以。 所以这个函数可以写为:

template<typename Ret, typename Param>
Deduced_Types<Ret, Param> deduce_type(Ret (*)(Param))
{
    return Deduced_Types<Ret, Param>();
}
它起作用了

那么现在来看看吧:

template< class F >
class Bar
{
public:
    typedef typename F::Return_type Func_Return_type;
    typedef typename F::Parameter_type Fun_Param_type;

};
现在,函数指针不再作为模板参数传递,而是作为参数传递:

void foo(int *p) {}

int *p;
bar b(foo, p); 
这里唯一的问题是类必须存储这个指针以备将来使用。

在C++17中,您可以这样做

template <auto> struct bar;

template<typename T, void (*F)(T*)>
struct bar<F>
{
    bar(T* t) { F(t); }
};
模板结构条;
模板
结构条
{
bar(T*T){F(T);}
};
使用方法:

int* p = nullptr;
bar<foo> b(p);
int* p = nullptr;
bar<decltype(&foo), &foo> b(p);
int*p=nullptr;
b条(p);
在C++17之前,您可以执行以下操作:

template <typename T, T> struct bar;

template<typename T, void (*F)(T*)>
struct bar<void (*)(T*), F>
{
    bar(T* t) { F(t); }
};
模板结构条;
模板
结构条
{
bar(T*T){F(T);}
};
使用方法:

int* p = nullptr;
bar<foo> b(p);
int* p = nullptr;
bar<decltype(&foo), &foo> b(p);
int*p=nullptr;
b条(p);
宏可用于删除重复项,例如:

#define BAR(Func) bar<decltype(&Func), &Func>
#define TYPE_AND_VALUE(V) decltype(V), V>
#定义栏(Func)栏
#定义类型和值(V)定义类型(V),V>
允许:

BAR(foo) b(p);
bar<TYPE_AND_VALUE(&foo)> b(p);
BAR(foo)b(p);
b条(p);

在我能看到的范围内(不是很近),你不能
T
处于不可推断的上下文中。您可以创建
F
一个类型化模板参数(与您现在的非类型化模板参数相反),然后通过模板化将演绎移动到构造函数中。我得考虑一下。即使在这种情况下,您也需要在
b
的decl上使用decltype。您需要一个需要C++17的
auto
模板参数。@n.m.如果您的意思是
template struct bar
,那么g++会给我
错误:“auto”参数在此上下文中是不允许的
不,这不是auto的工作方式。这是一种方法。谢谢@n.m。这很有效,但如果没有c++17,效果会更好。首选c++11>c++14>c++17我认为在函数指针本身而不是类型上进行模板化的目的是为放入的每个不同函数生成一个唯一的模板,但这不会实现,因为它是在函数类型上进行模板化的,因为他可以将声明更改为
template
,并将其用作
bar
,然后从类型F中提取T。
BAR(foo) b(p);
bar<TYPE_AND_VALUE(&foo)> b(p);