具有不同参数的函数容器

时间:2012-12-01 11:28:22

标签: c++ function templates pointers containers

有没有办法在向量中存储带有不同参数的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;
});

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

编辑:我解决了存储没有参数的函数的问题,所以这不再是问题的一部分,是什么让这个问题更加清晰明了。

3 个答案:

答案 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;
};

这就是我想到的,它运作得很好。但是,请随时建议改进或使用您自己项目的代码。