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

问题描述 投票:0回答:2

我希望能够传递一个函数,它接受任意数量的参数,加上匹配的参数,作为函数的参数。这是我到目前为止所尝试过的,因为我不太了解参数包的工作方式,所以我迷失了。

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()然后将结果函数作为参数传递来愚蠢地解决问题。我真的希望这样的电话。如果这不可能,那太糟糕但只有这样我才能检查其他解决方案。

c++ variadic-templates std-function template-deduction stdbind
2个回答
2
投票

你绑定了所有的参数,所以你的地图实际上将充满std::function<void()>,它将与传入的函数不匹配。您可以将lambdas与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)BindAction()收到一个std::function<void(T*, Args...)> const &,对于某些TArgs...类型要推断,但是你传递给它一个&Simulation::Test,所以指向类(结构)的(static?)方法,这不是std::function

你传递一个指针,可以转换为std::function但不是std::function

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

(2)你需要两个不同的参数类型的可变参数列表:Args1...参数的std::function列表和收到的参数(Args2...)的第二个args...列表。

查看您的通话示例

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

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

Test()方法接受floatstd::stringint;但BindAction()收到floatchar const [9]int

如果使用单个Args...列表,则编译器无法推断出类型,因为它有两个不同的类型列表。

(3)不确定但是......你的BindAction()是一个static方法但是使用(如果我理解正确的话)对象的一个​​成员(m_action

(4)你的BindAction()方法是一个void方法但返回一个函数 [改正]

建议:

(a)将callable作为模板类型本身接收,而不是推断出参数的类型

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

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

#include <functional>
#include <iostream>

template <typename F, typename ... As>
static auto BindAction (F const & func, As && ... args)
 { return std::bind(func, std::forward<As>(args)...); }

void Test(float f, std::string s, int i)
 { std::cout << "f[" << f << "], s[" << s << "], i[" << i << "]" << std::endl; } 

int main ()
 { 
   auto ba = BindAction(Test, 5.f, "a string", 2);

   std::cout << "post BindAction(), pre ba()\n";

   ba();
 }
© www.soinside.com 2019 - 2024. All rights reserved.