简体   繁体   English

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

[英]Container for pointers to member functions with different arguments

I am looking everywhere (Modern C++ design & co) but I can't find a nice way to store a set of callbacks that accept different arguments and operate on different classes. 我到处都在寻找(现代C ++设计和合作),但是我找不到一种好方法来存储一组接受不同参数并在不同类上运行的回调。 I need this because I would like every object of my application to have the possibility to defer the execution of one of its methods to a master Clock object that, keeping track of the current time, can call this methods in the right moment. 我之所以需要这样做,是因为我希望应用程序的每个对象都可以将其方法之一的执行推迟到主Clock对象上,该主Clock对象可以跟踪当前时间,可以在适当的时候调用此方法。 The code I am aiming for is something along the lines of: 我所针对的代码大致如下:

In the void executeAction1Deferred(int time, int arg1, bool arg2) method of class1 , where time is the execution time wanted in the future, there should be something like this: class1void executeAction1Deferred(int time, int arg1, bool arg2)方法中,其中time是将来所需的执行时间,应该是这样的:

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

In Clock::defer(??? what signature ????) an object that represents this Task is stored in a priority queue where the time is the Key. Clock::defer(??? what signature ????) ,代表此Task的对象存储在优先级队列中,其中时间是键。 For every Clock quantum the list of Tasks is then traversed and the tasks that need to be run in this quantum will be executed. 然后,将遍历每个“ Clock ”任务列表,然后执行需要在该任务中运行的任务。 Note that I have used "defer" as a static function because I intend the Clock object of a singleton, but it could also be a member function, it's just matter of choice. 请注意,我已经将“ defer”用作静态函数,因为我打算使用Singleton的Clock对象,但是它也可以是成员函数,这只是选择的问题。

I have thought of using void* to keep a variable number of the arguments, but having my action1() method accepting a void* is pretty terrible, also because I would need to craft a struct for the argument every time I use this function directly without deferring it. 我曾考虑过使用void*来保留可变数量的参数,但是让我的action1()方法接受void*确实很糟糕,这还因为每次我直接使用此函数时都需要为参数构造一个结构而不会推迟。

I have been facing this problems various times in the past, and I have never found a really decent solution. 过去,我多次遇到过这个问题,但从未找到真正合适的解决方案。 Please note that being this a small multi-platform project where the simplicity of building for the inexperienced programmers that could extend it is essential, I don't want to use boost. 请注意,由于这是一个小型的多平台项目,因此对于缺乏经验的程序员来说,构建简单的可以扩展的项目至关重要,我不想使用boost。 But, every compiler for the platforms we address have std::tr1 bind. 但是,我们处理的平台的每个编译器都有std::tr1绑定。 The question is: how to define a container of generic functions, each of these accepting a variable number of parameters (up to N ~ 5), and being a different member method of objects that do not derive from a common virtual class? 问题是:如何定义一个泛型函数的容器,每个泛型函数接受可变数量的参数(最多N〜5个),并且是不是从公共虚类派生的对象的不同成员方法? Thanks 谢谢

Use std::function<void()> to store the calls and then use a variadic template argument to forward and bind the function parameters: 使用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);
}

see also std::bind and std::mem_fun 另请参见std::bindstd::mem_fun

In C++11, store std::function<void()> . 在C ++ 11中,存储std::function<void()> You can use std::bind to create the function from one of a different signature, for example: 您可以使用std::bind从其他签名之一创建函数,例如:

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

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

If C++11 isn't an option, then Boost has very similar function and bind templates. 如果没有C ++ 11,则Boost具有非常相似的functionbind模板。 I think they might also exist in TR1, although I don't have any historical references to check. 我认为它们可能也存在于TR1中,尽管我没有任何历史参考可查。

If Boost really isn't an option (and TR1 doesn't provide these), then I strongly recommend that you make it an option; 如果Boost确实不是一个选项(而TR1不提供这些选项),那么我强烈建议您将其设为一个选项; otherwise, use Boost as an example of how to implement this. 否则,请使用Boost作为实现此方法的示例。 Without variadic templates, it gets very hairy. 没有可变参数的模板,它将变得非常毛茸茸。

(And since you mention Modern C++ Design, read the section on type lists; that's how you would do it without variadic templates). (并且由于您提到了Modern C ++ Design,因此请阅读类型列表中的部分;这就是不使用可变参数模板的方式)。

Since your callbacks get deferred including their provided arguments, the real signature will be void() , ie the Clock object won't provide arguments on its own and has no need to evaluate the results. 由于您的回调将包括其提供的参数而被推迟,因此实际的签名将为void() ,即Clock对象将不会自行提供参数,也无需评估结果。 So generally you will want to bind member function pointers (or other function pointers) together with the needed arguments and pass the result (a function object) to the clock. 因此,通常您会希望将成员函数指针(或其他函数指针)与所需的参数绑定在一起,并将结果(函数对象)传递给时钟。 This is where boost::bind / std::tr1::bind and boost::function / std::function<void()> come in - or C++11 lambdas: 这是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);} );

But what you are doing is already done - take a look at Boost.Asio timers: 但是您正在做的事情已经完成-看一下Boost.Asio计时器:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM