0

我到处寻找(现代 C++ 设计和合作),但我找不到一种很好的方法来存储一组接受不同参数并在不同类上操作的回调。我需要这个,因为我希望我的应用程序的每个对象都有可能将其方法之一的执行推迟到一个主Clock对象,该对象跟踪当前时间,可以在正确的时刻调用这个方法。我的目标是这样的代码:

在 的void executeAction1Deferred(int time, int arg1, bool arg2)方法中class1,time 是未来想要的执行时间,应该是这样的:

Clock::defer(time, Class1::action1, this, arg1, arg2);

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

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

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

4

3 回答 3

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

于 2012-12-04T13:32:16.593 回答
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++ 设计,请阅读类型列表部分;这就是您在没有可变参数模板的情况下如何做到的)。

于 2012-12-04T13:38:04.660 回答
1

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

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
于 2012-12-04T13:38:24.380 回答