使用任意参数调用数据成员函数的成员函数模板

Member function template to call a funcion on a data member with arbitrary arguments

我正在研究 C++11 代码库,想知道如何调用传递任意参数的成员类型上的任何函数。 请注意,因为我使用的是 C++11,所以我不能使用 std::invoke.

之类的东西

我开始在 Outer class 中创建函数模板,但我最初的尝试出现编译错误。

#include <iostream>
#include <utility>
#include <type_traits>

struct Inner {
  void bar(int x) {
    std::cout << "Called: x=" << x << std::endl;
  }
};

struct Outer {
  explicit Outer(Inner *i) : b{i} {}
  void foo(int) {}
  Inner* b;

  template <typename Func, typename ... Args>
  void CallInner(Func&& f, Args&& ... args) {
    b->f(std::forward<Args>(args)...);
  }
};


int main() {
  Inner inner{};
  Outer outer(&inner);
  outer.CallInner(&Inner::bar, 5);
}

Try it out yourself

同样,我想保持上面示例代码中函数的签名CallInner不变。

关于更改签名,您没有太多选择,因为至少需要一个额外的模板。

正确的语法有点复杂:

struct Outer {
  explicit Outer(Inner *i) : b{i} {}
  void foo(int) {}
  Inner* b;

    template <typename Ret, typename ...FuncArgs,  typename ... Args>
    void CallInner(Ret (Inner::*f)(FuncArgs...), Args&& ... args) {
        (b->*f)(std::forward<Args>(args)...);
  }
};

CallInner 的第一个参数必须是方法指针,并且在模板上下文中,它不仅需要通过一组可变模板参数 FuncArgs 进行模板化,而且它的 return 类型 Ret。然后,您还需要第二组可变参数模板参数,用于转发参数的转发引用(可能不一定与 FuncArgs 相同,因此需要单独的一组可变参数模板类型)。

因为 f 是一个指针,所以在调用它之前需要先取消引用它的成员函数:

(b->*f)(std::forward<Args>(args)...);