I have a template, more or less like this:
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;
};
it works, but I dont like the way I have to instantiate it:
Foo<SomeVeryLongClassName,&SomeVeryLongClassName::AnEvenLongerMemberFunctionName> f;
Is there some way I can make the template deduce T
?
I was thinking of a template method that I could call like this:
getFoo(&SomeVeryLongClassName::AnEvenLongerMemberFunctionName);
or, as I will mainly use Foo
inside T
, that would be just
getFoo(AnEvenLongerMemberFunctionName);
I tried this
#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); }
The error messages are actually quite clear, but I dont understand them at all...
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);
...why "wrong number of template arguments (1, should be 2)" ?
How can I help the compiler to deduce T
when instantiating a Foo
?
Is it possible with only pre-C++11?
PS: this is very close to being a dupe, but I really need to know the type of T
and not just call the member function (e.g. I need to create an instance).
In C++17 we have non-type template parameters with deduced types:
template <auto> struct Foo;
template <typename T, void (T::*MF)()> struct Foo<MF> {
// ...
};
Usage: Foo<&X::f>
You can also directly use template <auto X>
and either keep using auto
inside your template or use decltype(X)
to get at the type of the non-type parameter.
Prior to C++17, you could try to perform deduction via some contortions involving helper class templates with member function templates and decltype
.
The gory details:
If you define a function template template <typename T, void(T::*MF)()> Foo<T, MF> f(MF);
, where Foo is your old-style class template (like template <typename T, void (T::*MF)()> class Foo;
), then you can use decltype(f(&X::h))
to deduce the desired type Foo<X, &X::h>
without having to repeat X. The price is that you either need to say decltype
everywhere, or you wrap that in a macro.