如何从指向成员函数的指针推断出“T”的类型?
How to deduce type of `T` from a pointer to member function?
我有一个模板,大致是这样的:
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);
或者,因为我将主要在 T
中使用 Foo
,那将只是
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);
...为什么 "wrong number of template arguments (1, should be 2)"?
如何帮助编译器在实例化 Foo
时推导出 T
?
仅使用 C++11 之前的版本可能吗?
PS:this 非常接近于被骗,但我真的需要知道 T
的类型而不仅仅是调用成员函数(例如我需要创建一个实例)。
在 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 之前,您可以尝试通过一些涉及辅助 class 模板与成员函数模板和 decltype
的扭曲来执行推导。
血淋淋的细节:
如果你定义一个函数模板 template <typename T, void(T::*MF)()> Foo<T, MF> f(MF);
,其中 Foo 是你的旧式 class 模板(如 template <typename T, void (T::*MF)()> class Foo;
),那么你可以使用 decltype(f(&X::h))
来推导所需的类型 Foo<X, &X::h>
而不必重复 X。代价是您要么需要在任何地方都说 decltype
,要么将其包装在宏中。
我有一个模板,大致是这样的:
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);
或者,因为我将主要在 T
中使用 Foo
,那将只是
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);
...为什么 "wrong number of template arguments (1, should be 2)"?
如何帮助编译器在实例化 Foo
时推导出 T
?
仅使用 C++11 之前的版本可能吗?
PS:this 非常接近于被骗,但我真的需要知道 T
的类型而不仅仅是调用成员函数(例如我需要创建一个实例)。
在 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 之前,您可以尝试通过一些涉及辅助 class 模板与成员函数模板和 decltype
的扭曲来执行推导。
血淋淋的细节:
如果你定义一个函数模板 template <typename T, void(T::*MF)()> Foo<T, MF> f(MF);
,其中 Foo 是你的旧式 class 模板(如 template <typename T, void (T::*MF)()> class Foo;
),那么你可以使用 decltype(f(&X::h))
来推导所需的类型 Foo<X, &X::h>
而不必重复 X。代价是您要么需要在任何地方都说 decltype
,要么将其包装在宏中。