简体   繁体   中英

Passing a member function pointer as an argument to a template method

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM