我有一个模板,或多或少像这样:
template<typename T,void (T::*F)()>
struct Foo{
/* ... do some stuff with the member function pointer ...*/
//... e.g.
T foo(){
T t;
t.*F;
return t;
};
它有效,但我不喜欢我必须实例化它的方式:
Foo<SomeVeryLongClassName,&SomeVeryLongClassName::AnEvenLongerMemberFunctionName> f;
有什么方法可以让模板推断T
?
我在想一个模板方法,我可以这样称呼:
getFoo(&SomeVeryLongClassName::AnEvenLongerMemberFunctionName);
或者,因为我将主要使用Foo
内的T
,这只是
getFoo(AnEvenLongerMemberFunctionName);
我试过这个
#include <iostream>
template <typename T,void (T::*MEMFUN)()>
struct Foo{};
template <typename T,void (T::*MEMFUN)()>
Foo<typename T,typename MEMFUN> getFoo(MEMFUN f){
return Foo<typename T,typename MEMFUN>();
}
struct Bar { void test(){ std::cout << "MUH" << std::endl;} };
int main (){ getFoo(&Bar::test); }
错误信息实际上非常清楚,但我根本不理解它们......
templateExample.cpp:9:28: error: wrong number of template arguments (1, should be 2)
Foo<typename T,typename MEMFUN>
^
templateExample.cpp:4:8: error: provided for ‘template<class T, void (T::* MEMFUN)()> struct Foo’
struct Foo{
^
templateExample.cpp:10:7: error: invalid type in declaration before ‘(’ token
getFoo(MEMFUN f){
^
templateExample.cpp:10:7: error: template declaration of ‘int getFoo’
templateExample.cpp:10:15: error: expected ‘)’ before ‘f’
getFoo(MEMFUN f){
^
templateExample.cpp: In function ‘int main()’:
templateExample.cpp:20:20: error: ‘getFoo’ was not declared in this scope
getFoo(&Bar::test);
...为什么“错误的模板参数数量(1,应该是2)”?
如何在实例化T
时帮助编译器推断Foo
?
只有pre-C ++ 11才有可能吗?
PS:this非常接近欺骗,但我真的需要知道T
的类型,而不仅仅是调用成员函数(例如我需要创建一个实例)。
答案 0 :(得分:4)
在C ++ 17中,我们有非类型模板参数和推导类型:
template <auto> struct Foo;
template <typename T, void (T::*MF)()> struct Foo<MF> {
// ...
};
用法:Foo<&X::f>
您也可以直接使用template <auto X>
并继续在模板中使用auto
或使用decltype(X)
获取非类型参数的类型。
在C ++ 17之前,您可以尝试通过一些涉及成员函数模板和decltype
的辅助类模板的扭曲来执行演绎。
血淋淋的细节:
如果您定义了一个函数模板template <typename T, void(T::*MF)()> Foo<T, MF> f(MF);
,其中Foo是您的旧式类模板(如template <typename T, void (T::*MF)()> class Foo;
),那么您可以使用decltype(f(&X::h))
推导出所需的类型{{1无需重复X.价格是您需要在任何地方说Foo<X, &X::h>
,或者将其包装在宏中。