将成员函数指针作为参数传递给模板方法

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

我正在尝试编写一个接受成员函数指针作为参数的模板化方法。

这里有一个例子class,包括我最近尝试写的模板方法:

class MyClass
{
public:
   int myMethod() { return 1; }

   template<typename T> 
   T call(std::function<T(MyClass*)> m)
   {
      return m(this);
   }
};

我的目标是能够执行以下操作(或语法上非常相似的操作):

MyClass m;
auto result = m.call(&MyClass::myMethod);

到目前为止,通过我上面的尝试,我可以做到:

MyClass m;
std::function<int(MyClass*)> f = &MyClass::myMethod;
auto result = m.call(f);

令我惊讶的是,我什至无法将其包装成一行。 m.call(&MyClass::myMethod) 这不编译。为什么?

我确信有一种方法可以获得我想要的行为,因此非常感谢任何帮助!

显然它无法推导 T(来自非常推导的 ctor 参数的模板参数)。

如果您的目标只是在一次调用中完成,您可以将方法定义更改为类似

    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?

成员函数指针具有以下类型

<return-type>(ClassType::*)(<args>)<specifiers-if-any>

意思是&MyClass::myMethod有类型

int(MyClass::*)(void)

这不等于 std::function<int(MyClass*)> 类型,编译器无法直接推导它,因此出现编译错误。

但是,如果我们显式只提及模板类型,则可以推导出std::function<int(MyClass*)>,与some type erasur overheads。这意味着您可以像下面这样明确提及模板参数:

/* 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[...]

如果您不使用 std::function 而是正常的(模板化的)成员函数指针类型,这将起作用。

template<typename T>
T call(T(MyClass::* m)())
{
   return (this->*m)();
   // or
   // std::invoke(m, this); // in C++17
}

现在你可以

/* const */ int result = m.call(&MyClass::myMethod);

(See Live Demo)


如果语法令人困惑,您可以像这样为成员函数指针提供一个模板类型别名。

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
   }
};