gpt4 book ai didi

c++ - 在一个函数容器中存储和调用不同参数的函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:43:41 24 4
gpt4 key购买 nike

这是我想要实现的示例设计代码。基本上我想为不同的 handlerNames 存储处理函数,这些处理函数可以是可变参数。

应该在事件上调用处理函数,所需参数通过 Script::Handle(...) 传递

我怎样才能做到这一点?可变参数模板可能可行吗?

class Script
{
public:
Script() { /* ... */ }

template<typename TFunction>
void AddHandler(const char *handlerName, TFunction &&function)
{
_handlerMap[handlerName] = std::move(function);
}

void Handle(const char *handlerName, ...)
{
_handlerMap[handlerName](...);
}

private:
typedef std::map<std::string, std::function<void()>> HandlerMapType;
HandlerMapType _handlerMap;
};

//Handler functions
handlerOne() { std::cerr << "One"; }
handlerTwo(std::string a1, int a2) { std::cerr << "Two"; }
handlerThree(bool a1) { std::cerr << "Three"; }

int main(int argc, char **argv)
{
Script script;
script.AddHandler("One", std::bind(&handlerOne));
script.AddHandler("Two", std::bind(&handlerTwo));
script.AddHandler("Three", std::bind(&handlerThree));

script.Handle("One");
script.Handle("Two, "string", 96);
script.Handle("Three", true);

script.Handle("Three", "what should happen here?"); //String passed instead of bool
}

最佳答案

让我先声明这在 C++ 中不是一件微不足道的事情。我会尽可能说你应该考虑这是否真的是你用例中需要的东西。在您的示例中,您要求的是您无法真正使用的通用性。在任何情况下,您都需要知道您正在调用的函数的签名才能正确调用它;在那种情况下,将它们放入容器中有什么目的?

通常,如果您正在编写中间层代码,您会这样做。在您的示例中,这等同于编写使另一个用户能够调用 Handle 的代码。一个常见的具体示例是编写一个工厂,工厂中的对象可以使用不同的参数进行实例化。然而,这不可能真的是“不同”的论点,至少不是没有一些疯狂的 Actor 。解决方案是使所有函数都采用相同的参数,但使参数成为可以存储您想要的任何参数的动态类型:

using argument_type = std::unordered_map<std::string, boost::any>;

void print(const argument_type & arg) {
auto to_print = boost::any_cast<std::string>(arg["to_print"]);
std::cerr << to_print << std::endl;
}

void print_none(const argument_type & arg) {
std::cerr << "none" << std::endl;
}

using my_func_t = std::function<void(const argument_type &)>;

std::vector<my_func_t> v;
v.emplace_back(print);
v.emplace_back(print_none);

// create some argument_types, feed them to f.

以上不是经过测试的代码,也不是可用的主代码,但我认为这应该让您了解如何完成您想要的。

edit:我仔细考虑了一下,决定详细说明一下“疯狂类型转换”的方式。我想这并没有更疯狂,但我非常喜欢上面展示的内容。另一种方法是完全键入删除函数本身,并使用可变参数模板传递参数。

void print(std::string to_print) {
std::cerr << to_print << std::endl;
}

void print_none() {
std::cerr << "none" << std::endl;
}


std::vector<boost::any> v;
v.emplace_back(std::function<void(std::string)>(print));
v.emplace_back(std::function<void(void)>(print_none));

template <typename ... Args>
void call(const std::vector & funcs, int index, Args... args) {
auto f = boost::any_cast<std::function<void(Args...)>>(funcs[index]);
f(std::forward<Args>(args)...);
}

// unsure if this will actually work
call(f, 0, std::string("hello"));

上面的代码非常脆弱,因为你传递给 call 的类型将被推导,然后转换将尝试转换为与该签名匹配的 std::function。那个确切的签名。我不太相信这会成功。如果它是引用、vs 值、vs 右值等。转换回与您输入的不同的 std::function 是未定义的行为。

总而言之,我要么尽量避免完全这样做,要么采用第一种解决方案。它不那么脆弱,最好提前说明您正在删除这些函数的签名这一事实。

关于c++ - 在一个函数容器中存储和调用不同参数的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31039471/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com