有没有办法推断出函数指针模板参数的值?

时间:2013-07-19 00:41:20

标签: c++ templates non-type template-deduction

C ++允许非类型模板参数为指针,包括函数指针,类型。我最近向question询问了有用的内容,这是对one of the answers的跟进。

从函数指针中推断函数指针模板参数的是否可行?例如:

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

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

如果您对此背后的动机感到疑惑,请参阅this answer下的评论,尤其是std::bind()实施的可能优化。

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

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

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

然后可以打电话

templ(func);

templ<func>();

并且只需提及函数指针即可推导出类型和值。

希望现在更有意义。

1 个答案:

答案 0 :(得分:2)

函数的模板参数是从函数模板参数的类型推导出来的。模板参数只能在类型是允许的表单之一时从类型推导出来。允许的表单在[temp.deduct.type]

中指定
  

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

     

如果TTTiP,则可以推导出模板类型参数A,模板模板参数(T)或模板非类型参数T以下形式之一:

T
cv-list T
T*
T&
T[integer-constant]
template-name (where template-name refers to a class template)
type(*)(T)
T(*)()
T(*)(T)
T type::*
type T::*
T T::*
T (type::*)()
type (T::*)()
type (type::*)(T)
type (T::*)(T)
T (type::*)(T)
T (T::*)()
T (T::*)(T)
type[i]
template-name<i> (where template-name refers to a class template)
TT<T>
TT<i>
TT<>
  

其中()表示参数列表,其中至少一个参数类型包含T<T>表示参数列表,其中没有参数包含T。类似地,<i>表示模板参数列表,其中至少一个参数包含i<>表示模板参数列表,其中至少一个参数包含T和{{1} }表示模板参数列表,其中没有参数包含ii

仅考虑非类型模板参数时,相关表单是包含NonType

的表单
type[i]
template-name<i> (where template-name refers to a class template)
TT<i>

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

以下代码通过将非类型模板参数值包装在名为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_TYPENonType宏仅为方便起见,以避免必须写出{{1}}的完整模板参数列表