指向具有不同参数的成员函数的指针的容器

时间:2012-12-04 13:24:56

标签: c++ templates callback scheduling generic-programming

我到处寻找(Modern C ++ design& co)但我找不到一种很好的方法来存储一组接受不同参数并在不同类上运行的回调。我需要这个,因为我希望我的应用程序的每个对象都有可能将其中一个方法的执行推迟到一个主Clock对象,跟踪当前时间,可以在右边调用这些方法时刻。我的目标代码是:

void executeAction1Deferred(int time, int arg1, bool arg2)的{​​{1}}方法中,时间是将来需要的执行时间,应该是这样的:

class1

Clock::defer(time, Class1::action1, this, arg1, arg2); 中,表示此任务的对象存储在优先级队列中,其中时间是密钥。对于每个Clock::defer(??? what signature ????)量程,然后遍历任务列表,并执行需要在此量程中运行的任务。请注意,我使用“defer”作为静态函数,因为我打算使用单例的Clock对象,但它也可以是成员函数,这只是选择的问题。

我曾考虑使用Clock来保留可变数量的参数,但让我的void*方法接受action1()非常可怕,因为我需要制作一个每次我直接使用这个函数而不推迟它的参数的结构。

我过去曾多次面对这些问题,而且我从来没有找到一个非常好的解决方案。请注意,作为一个小型的多平台项目,为缺乏经验的程序员构建简单性可以扩展它是必不可少的,我不想使用boost。但是,我们处理的平台的每个编译器都有void*绑定。问题是:如何定义泛型函数的容器,每个函数接受可变数量的参数(最多N~5),并且是不是从公共虚拟类派生的对象的不同成员方法?感谢

3 个答案:

答案 0 :(得分:7)

使用std::function<void()>存储调用,然后使用可变参数模板参数转发和绑定函数参数:

class Clock
{
    vector<function<void()>> tasks;

    template<class F, class... Args>
    void defer(F f, Args&&... args)
    {
        tasks.push_back(bind(f, forward<Args>(args)...);
    }

}

void f(A a, B b);

int main()
{
    A a;
    B b;

    Clock c;
    c.push_back(f, a, b);
}

另请参阅std::bindstd::mem_fun

答案 1 :(得分:2)

在C ++ 11中,存储std::function<void()>。您可以使用std::bind从其中一个签名创建函数,例如:

std::vector<std::function<void()>> deferred;
deferred.push_back(std::bind(&Class1::action1, this, arg1, arg2));

// later...
for (auto f : deferred) f();

如果C ++ 11不是一个选项,那么Boost具有非常相似的functionbind模板。我认为它们也可能存在于TR1中,虽然我没有任何历史参考来检查。

如果Boost真的不是一个选项(并且TR1不提供这些选项),那么我强烈建议您选择它;否则,使用Boost作为如何实现它的示例。如果没有可变参数模板,它会非常毛茸茸。

(既然你提到了现代C ++设计,请阅读关于类型列表的部分;如果没有可变参数模板,那就是这样做的。)

答案 2 :(得分:1)

由于你的回调被推迟包括他们提供的参数,真正的签名将是void(),即Clock对象不会自己提供参数,也不需要评估结果。因此,通常您需要将成员函数指针(或其他函数指针)与所需参数绑定在一起,并将结果(函数对象)传递给时钟。这是boost::bind / std::tr1::bindboost::function / std::function<void()>进来的地方 - 或C ++ 11 lambdas:

Clock::defer(time, boost::bind(&Class1::action1, this, arg1, arg2));
//C++11 lambda:
Clock::defer(time, [=](){action1(arg1, arg2);} );

但你正在做的事情已经完成 - 看看Boost.Asio计时器:

boost::asio::basic_deadline_timer timer(ioService, expiryTime);
timer.async_wait([=](){action1(arg1, arg2);} //perform action1 when the timer is done