具有不同参数的函数的容器

Container of Functions with different Parameters

本文关键字:函数 参数      更新时间:2023-10-16

有没有一种方法可以在向量中存储具有不同参数的void函数?参数的数量总是一个,只有类型不同。参数类型可以是默认类型(如int)、指向我自己对象的指针(如example*)或任何其他类型。

我现在所做的是使用一个函数向量和一个void指针作为参数。这样我就可以通过所有的考试。但我想去掉所有函数中的后铸。

unordered_map<string, function<void(void*)> > List;
void Callback(string Name, function<void(void*)> Function)
{
List[Name].push_back(&Function);
}
Callback("event", [](void* x){
int value = *(int*)x;
cout << value << endl;
});

这里有一个例子来说明我想要什么。请注意我更喜欢的模板语法。因此,我需要将所有函数存储在一个容器中。

vector<function<void(...)> > List; // need something other than a std vector
template <typename T>
void Callback(string Name, function<void(T)> Function)
{
List[Name].push_back(&Function);
}
Callback<int>([](int x){
cout << x << endl;
});

此应用程序与性能相关,因为它是实时渲染引擎的重要组成部分。

编辑:我解决了在没有参数的情况下存储函数的问题,所以这不再是问题的一部分,是什么使问题更加清晰和直接。

如果可以传递给函数的参数类型有限,那么一个选项是使用类似boost::variant:的东西

typedef boost::variant<
std::function<void()>,
std::function<void(int)>,
std::function<void(long)>,
std::function<void(std::string const&)>
> my_functions;
typedef std::vector<my_functions> functions_list;

然后您可以将回调直接插入到容器中。

正如n.m在评论中指出的那样,问题在于如何使用价值形式上,C++允许您将任何指针转换为(非成员)函数到void (*)(void)并返回到其原始类型,不损失价值—void (*)(void)可以可以被认为是一种用于指向函数的指针的CCD_ 5。和实际上,这种转换的运行时成本为零。但是为了使用该函数,在某个时刻,您必须知道原始类型,以便将指针转换回它。

你没有给出你的用例,但通常的情况包括回调,其中回调的注册具有void (*)( void* )(或void (*)( void const* )),并且回调将void*转换为正确的类型,并调用成员函数。在这种情况下,使用void*作为泛型论点是正确的(可能也是唯一的)解决方案。

当然,这是C的解决方案,通常只应该是当使用回调的接口是使用C API(例如pthread_create等函数)。在C++中,解决方案是注册对象,这些对象派生自抽象基类,并实现特定的纯虚拟作用

我开发了一个基于void指针的事件系统,它现在可以工作了。它使用模板来传递和接收数据。不支持任何类型的函数或同时支持一个参数。由于它使用了void指针来存储回调函数,我想和使用boost框架中任何类型的解决方案相比,它的速度都非常快。

#include <string>
#include <vector>
#include <unordered_map>
#include <functional> 
#include <memory>
using namespace std;
class ManagerEvent
{
typedef unordered_map<string, unordered_map<int, vector<pair<void*, bool> > > > Events;
public:
void Listen(string Name, function<void()> Function)
{
Listen(Name, 0, Function);
}
void Listen(string Name, int State, function<void()> Function)
{
List[Name][State].push_back(make_pair(new function<void()>(Function), false));
}
template <typename T>
void Listen(string Name, function<void(T)> Function)
{
Listen<T>(Name, 0, Function);
}
template <typename T>
void Listen(string Name, int State, function<void(T)> Function)
{
List[Name][State].push_back(make_pair(new function<void(T)>(Function), true));
}
void Fire(string Name)
{
Fire(Name, 0);
}
void Fire(string Name, int State)
{
auto Functions = List[Name][State];
for (auto i = Functions.begin(); i != Functions.end(); ++i)
{
if(i->second) continue;
else          (*(function<void()>*)(i->first))();
}
}
void FireRange(string Name, int From, int To)
{
for(int i = From; i <= To; ++i) Fire(Name, i);
}
template <typename T>
void Fire(string Name, T Data)
{
Fire(Name, 0, Data);
}
template <typename T>
void Fire(string Name, int State, T Data)
{
auto Functions = List[Name][State];
for (auto i = Functions.begin(); i != Functions.end(); ++i)
{
if(i->second) (*(function<void(T)>*)i->first)(Data);
else          (*(function<void()>*)i->first)();
}
}
private:
Events List;
};

这就是我想到的,而且效果很好。但是,请随时提出改进建议或将代码用于您自己的项目。