将模板可变参数函数及其参数传递给函数

时间:2019-02-24 18:20:30

标签: c++ variadic-templates std-function template-deduction stdbind

我希望能够传递带有任意数量的参数以及匹配参数的函数作为函数的参数。到目前为止,这是我尝试过的方法,但由于对参数包的工作方式了解得不多,我迷路了。

template <class T, typename... Args>
static void BindAction(const std::string& name, T* owner, const std::function<void(T*, Args...)>& func, Args... args)
{
    for (InputAction& action : m_actions)
        if (action.m_name == name)
            action.BindFunction(std::bind(func, owner, args...));
}

然后我用这些进行测试:

void Test(float f, std::string s, int i);

BindAction<Simulation>("Test", this, &Simulation::Test, 5.f, "a string", 2);

错误很简单,因为没有函数模板“ BindAction()”的实例与参数列表匹配。

请不要通过告诉我调用std::bind()然后将结果函数作为参数传递来解决问题。我真的希望这样打电话。如果这不可能,那就太糟糕了,但是只有这样我才能检查其他解决方案。

2 个答案:

答案 0 :(得分:2)

您将绑定所有参数,因此您的映射实际上将充满std::function<void()>,它将与传入函数不匹配。您可以将lambda与std::invoke结合使用以获得更可预测的结果,并且只需使用模板即可推断出传入可调用的类型:

#include <functional>
#include <iostream>

class Actions {
 public:
  template <typename F, typename... Args>
  void BindAction(const std::string& name, F f, Args... args) {
    actions_.emplace(
      name,
      [f, args...] () mutable { return std::invoke(f, args...); }
    );
  }

  void call(const std::string& name) {
    actions_[name]();
  }

 private:
  std::unordered_map<std::string, std::function<void()>> actions_;
};

还有一个简单的使用示例:

class Cls {
  public:
    void do_func(int i) {
      std::cout << "Cls::do_func(" << i << ")\n";
    }
};

int main() {
  Cls c;
  Actions actions;
  actions.BindAction("test", &Cls::do_func, c, 1);
  actions.call("test");
}

答案 1 :(得分:1)

代码中有一些问题。

无特定顺序

(1)BindAction()收到std::function<void(T*, Args...)> const &,对于某些T e Args...类型可以推导,但是您将其传递给&Simulation::Test,因此指向类/结构(static的(std::function?)方法的指针。

您传递了一个可以转换为std::function但不是std::function的指针。

一种鸡蛋和鸡肉的问题:编译器无法将指针转换为std::function,因为它不知道Args...类型,也无法推导Args...类型因为没有收到std::function

(2)您需要两个不同的参数类型可变参数列表:Args1...的{​​{1}}列表和第二个std::function的参数列表({{1} })。

查看您的通话示例

Args2...

args...方法收到一个void Test(float f, std::string s, int i); BindAction<Simulation>("Test", this, &Simulation::Test, 5.f, "a string", 2); ,一个Test()和一个float;但是std::string收到intBindAction()float

如果您使用单个char const [9]列表,则编译器将无法推断出类型,因为它具有两个不同的类型列表。

(3)不确定,但是...您的intArgs...方法,但使用(如果我理解正确的话)对象(BindAction())的成员

(4)您的static方法是m_action方法,但是返回了一个函数 [更正]

建议:

(a)本身作为模板类型接收可调用对象,而没有推断出参数的类型

(b)接收参数列表作为通用引用,并使用模板转发

为显示一个简化的示例,如下所示

BindAction()