I am trying to write a templated method that will accept a member function pointer as an argument.
Here is an example class, including my latest attempt to write said template method:
class MyClass
{
public:
int myMethod() { return 1; }
template<typename T>
T call(std::function<T(MyClass*)> m)
{
return m(this);
}
};
My goal is to be able to do the following (or something very similar in syntax):
MyClass m;
auto result = m.call(&MyClass::myMethod);
So far with my attempt above, I can do:
MyClass m;
std::function<int(MyClass*)> f = &MyClass::myMethod;
auto result = m.call(f);
I was surprised I was not even able to wrap that into a single line. m.call(&MyClass::myMethod)
this does not compile. Why?
I am sure there is a way to get the behaviour I want, so any help would be much appreciated!
Apparently it cannot deduce T
(template parameter from a very deduced ctor argument).
If your goal is to simply do it in one call you can change method definition to something like
template<class F> auto call(F &&f) {
return std::invoke(std::forward<F>(f), this);
}
I was surprised I was not even able to wrap that into a single line.
m.call(&MyClass::myMethod)
... this does not compile. Why?
The member function pointer has the following type
<return-type>(ClassType::*)(<args>)<specifiers-if-any>
meaning &MyClass::myMethod
has the type
int(MyClass::*)(void)
This is not equal to the type std::function<int(MyClass*)>
and the compiler can not directly deduce it, hence the compiler error.
However, if we explicit ly mention the template type, it can be deduced to std::function<int(MyClass*)>
, with some type erasur overheads . Meaning you could mention the template parameter explicitly like as follows:
/* const */ int result = m.call<int>(&MyClass::myMethod); // works!
// ^^^^^^ -> mention T == int here!
( See Live Demo )
I'm sure there's a way to get the behaviour[...]
If you do not use std::function
rather the normal (templated) member function pointer type , this will work.
template<typename T>
T call(T(MyClass::* m)())
{
return (this->*m)();
// or
// std::invoke(m, this); // in C++17
}
Now you could
/* const */ int result = m.call(&MyClass::myMethod);
( See Live Demo )
If the syntax is confusing you could provide a template type alias for the member function pointer like this.
class MyClass
{
// template type alias
template<typename T> using MemFunctionPtrT = T(MyClass::*)();
public:
// other codes
template<typename T>
T call(MemFunctionPtrT<T> m) // use the alias type like
{
return (this->*m)();
// or
// std::invoke(m, this); // in C++17
}
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.