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>();
并且只需提及函数指针即可推导出类型和值。
希望现在更有意义。
答案 0 :(得分:2)
函数的模板参数是从函数模板参数的类型推导出来的。模板参数只能在类型是允许的表单之一时从类型推导出来。允许的表单在[temp.deduct.type]
中指定模板参数可以在几个不同的上下文中推导出来,但在每种情况下,根据模板参数(称为
P
)指定的类型与实际类型进行比较(称之为A
),并且尝试在替换之后查找将生成P
的模板参数值(类型参数的类型,非类型参数的值或模板参数的模板)。推导出的值(称之为推导的A
),与A
兼容。如果
T
和TT
有i
和P
,则可以推导出模板类型参数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} }表示模板参数列表,其中没有参数包含i
或i
。
仅考虑非类型模板参数时,相关表单是包含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_TYPE
和NonType
宏仅为方便起见,以避免必须写出{{1}}的完整模板参数列表