Container for pointers to member functions with different arguments

前端 未结 3 479
南方客
南方客 2021-01-17 05:41

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 classe

相关标签:
3条回答
  • 2021-01-17 06:17

    In C++11, store std::function<void()>. You can use std::bind to create the function from one of a different signature, for example:

    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. I think they might also exist in TR1, although I don't have any historical references to check.

    If Boost really isn't an option (and TR1 doesn't provide these), then I strongly recommend that you make it an option; otherwise, use Boost as an example of how to implement this. 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).

    0 讨论(0)
  • 2021-01-17 06:19

    Use std::function<void()> to store the calls and then use a variadic template argument to forward and bind the function parameters:

    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

    0 讨论(0)
  • 2021-01-17 06:24

    Since your callbacks get deferred including their provided arguments, the real signature will be void(), i.e. the Clock object won't provide arguments on its own and has no need to evaluate the results. 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:

    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::basic_deadline_timer timer(ioService, expiryTime);
    timer.async_wait([=](){action1(arg1, arg2);} //perform action1 when the timer is done
    
    0 讨论(0)
提交回复
热议问题