我希望能够传递一个函数,它接受任意数量的参数,加上匹配的参数,作为函数的参数。这是我到目前为止所尝试过的,因为我不太了解参数包的工作方式,所以我迷失了。
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()
然后将结果函数作为参数传递来愚蠢地解决问题。我真的希望这样的电话。如果这不可能,那太糟糕但只有这样我才能检查其他解决方案。
你绑定了所有的参数,所以你的地图实际上将充满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)BindAction()
收到一个std::function<void(T*, Args...)> const &
,对于某些T
和Args...
类型要推断,但是你传递给它一个&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()
方法接受float
,std::string
和int
;但BindAction()
收到float
,char 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();
}