7

C++允许非类型模板参数为指针,包括函数指针、类型。我最近问了一个关于这有什么用的问题,这是对其中一个答案的跟进。

是否可以从作为相关函数指针的函数参数中推断出函数指针模板参数的值?例如:

using VoidFunction = void(*)();

template <VoidFunction F>
void templ(VoidFunction);

...

void func();  // a VoidFunction

...

templ<func>(func);  // works, but I have to specify the template parameter explicitly
templ(func);        //  <-- I would like to be able to do this

有没有办法让这个扣除发生?从编译器实现者的角度来看,这在技术上似乎是可行的,只要函数参数可以在编译时解析为代码中的函数。

如果您想知道这背后的动机,请参阅此答案下的评论,特别是对std::bind().

编辑:我意识到我可以简单地删除函数参数并使用模板参数,如templ<func>(). 我添加函数参数的唯一目的是尽量避免传递模板参数。

我想我真正想要的是也推断出函数指针的类型,如:

template <typename Function, Function F>
void templ(/* something */);

然后就可以打电话了

templ(func);

或者

templ<func>();

并从函数指针的一次提及中推断出类型和值。

希望现在更有意义。

4

1 回答 1

3

函数的模板参数是从函数模板参数的类型推导出来的。只有当该类型是允许的形式之一时,才能从该类型推导出模板参数。允许的形式在 [temp.deduct.type] 中指定

可以在几种不同的上下文中推导出模板参数,但在每种情况下,都会将根据模板参数指定的类型(调用它P)与实际类型(调用它A)进行比较,并尝试查找模板参数值(类型参数的类型、非类型参数的值或模板参数的模板)P在替换推导的值(称为推导的A)后,将与 . 兼容A

一个模板类型实参T、一个模板模板实参TT或一个模板非类型实参i可以被推导出来,如果P并且A具有以下形式之一:

吨
简历列表 T
时间*
T&
T[整数-常数]
模板名称(其中模板名称是指类模板)
类型(*)(T)
T(*)()
T(*)(T)
T型::*
类型 T::*
TT::*
T (类型::*)()
类型 (T::*)()
类型(类型::*)(T)
类型 (T::*)(T)
T (类型::*)(T)
T (T::*)()
T (T::*)(T)
类型[i]
template-name<i>(其中 template-name 指的是类模板)
TT<T>
TT<i>
TT<>

where(T)表示至少一个参数类型包含 a 的参数列表T,并()表示没有参数包含 a 的参数列表T。类似地,表示至少一个实参包含 a 的模板实参列表,表示<T>至少一个实参包含 a 的模板实参列表,以及表示没有实参包含 a或 an 的模板实参列表。T<i>i<>Ti

当只考虑非类型模板参数时,相关的形式是那些包含i

类型[i]
template-name<i>(其中 template-name 指的是类模板)
TT<i>

因此,不可能直接从作为函数指针的函数参数的值推导出该值。但是,如果函数参数具有指定形式之一,可以推断非类型模板参数的值。

以下代码通过将非类型模板参数值包装在名为NonType. 的形参f形式为template-name<i>,使得推导其非类型模板实参的值成为可能。

template<typename T, T value>
struct NonType {};

template<typename T, T value>
void f(NonType<T, value>)
{
}

void g();

struct A
{
    void f();
    int m;
};

int i;

#define MAKE_NONTYPE(value) NonType<decltype(value), (value)>()

int main()
{
    f(MAKE_NONTYPE(0)); // NonType<int, 0>
    f(MAKE_NONTYPE(&g)); // NonType<void(*)(), &g>
    f(MAKE_NONTYPE(&A::f)); // NonType<void(A::*)(), &A::f>
    f(MAKE_NONTYPE(&A::m)); // NonType<int A::*, &A::m>
    f(MAKE_NONTYPE(&i)); // NonType<int*, &i>
}

请注意,decltype这里MAKE_NON_TYPE使用宏只是为了方便,以避免写出完整的模板参数列表NonType

于 2013-07-23T10:16:24.260 回答