有没有办法在向量中存储带有不同参数的void函数?参数的数量始终为1,只有类型不同。参数类型可以是默认类型,如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;
});
此应用程序与性能相关,因为它是实时渲染引擎的重要组成部分。
编辑:我解决了存储没有参数的函数的问题,所以这不再是问题的一部分,是什么让这个问题更加清晰明了。
答案 0 :(得分:1)
如果传递给函数的参数类型有限,那么一个选项就是使用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;
然后您可以将回调直接插入容器中。
答案 1 :(得分:1)
正如n.m在评论中指出的,问题是你如何使用
值。形式上,C ++允许您将任何指针转换为
(非成员)函数到void (*)(void)
并返回到它
原始类型,没有价值损失 - void (*)(void)
可以
被认为是一种void*
指向函数的指针。和
实际上,这种转换的运行时成本为零。但
为了使用该功能,在某些时候,你必须知道
原始类型,以便将指针转换回它。
您没有提供您的用例,但通常情况涉及
回调,其中回调的注册具有void
(*)( void* )
(或void (*)( void const* )
),以及回调
将void*
转换为正确的类型,并调用成员
功能就可以了。在这种情况下,使用void*
作为通用
参数是正确的(可能是唯一的)解决方案。
当然,这是C解决方案,通常应该只是
使用回调定义使用回调的接口时使用
C API(例如pthread_create
之类的函数)。在C ++中,
解决方案是注册从中派生的对象
抽象基类,并实现特定的纯虚拟
功能
答案 2 :(得分:0)
我开发了一个基于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;
};
这就是我想到的,它运作得很好。但是,请随时建议改进或使用您自己项目的代码。