1

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

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

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

4

3 回答 3

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;

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

于 2012-12-01T11:35:02.590 回答
1

正如 nm 在评论中指出的那样,问题在于您如何使用该值。形式上,C++ 允许您将任何指向(非成员)函数的指针转换为 avoid (*)(void)并返回其原始类型,而不会丢失值——void (*)(void)可以被认为是void*指向函数的指针的一种。实际上,此类转换的运行时间成本为零。但是为了使用该函数,在某些时候,您必须知道原始类型,以便将指针转换回它。

您没有给出您的用例,但通常情况涉及回调,其中回调的注册有一个void (*)( void* )(或void (*)( void const* )),并且回调将 转换void*为正确的类型,并在其上调用成员函数。在这种情况下,使用void*作为通用参数是正确的(并且可能是唯一的)解决方案。

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

于 2012-12-01T12:02:15.713 回答
1

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

#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;
};

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

于 2012-12-07T13:19:34.620 回答