Question

Is there a method/pattern/library to do something like that (in pseudo-code):

task_queue.push_back(ObjectType object1, method1);
task_queue.push_back(OtherObjectType object2, method2);

so that I could do the something like:

for(int i=0; i<task_queue.size(); i++) {
    task_queue[i].object -> method();
}

so that it would call:

obj1.method1();
obj2.method2();

Or is that an impossible dream?

And if there's a way to add a number of parameters to call - that would be the best.

Doug T. please see this Excellent answer!

Dave Van den Eynde's version works well too.

Was it helpful?

Solution

Yes you would want to combine boost::bind and boost::functions its very powerful stuff.

This version now compiles, thanks to Slava!

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <vector>

class CClass1
{
public:
    void AMethod(int i, float f) { std::cout << "CClass1::AMethod(" << i <<");\n"; }
};

class CClass2
{
public:
    void AnotherMethod(int i) { std::cout << "CClass2::AnotherMethod(" << i <<");\n"; }
};

int main() {
    boost::function< void (int) > method1, method2;
    CClass1 class1instance;
    CClass2 class2instance;
    method1 = boost::bind(&CClass1::AMethod, class1instance, _1, 6.0) ;
    method2 = boost::bind(&CClass2::AnotherMethod, class2instance, _1) ;

    // does class1instance.AMethod(5, 6.0)
    method1(5);

    // does class2instance.AMethod(5)
    method2(5);


    // stored in a vector of functions...
    std::vector< boost::function<void(int)> > functionVec;
    functionVec.push_back(method1);
    functionVec.push_back(method2);

    for ( int i = 0; i < functionVec.size(); ++i)
    {         
         functionVec[i]( 5);
    };
    return 0;
};

OTHER TIPS

Since C++ does not support heterogenous containers, your objects will have to have a shared base (so you can get away with having a container for pointers to this base class).

class shared_base {
     public:
     virtual void method() = 0; // force subclasses to do something about it
};

typedef std::list<shared_base*> obj_list;

class object : public shared_base {
     public:
     virtual void method() { methodx(); }
     private:
     int methodx(); 
};

// ...
list.insert(new object);

// ...
std::for_each(list.begin(), list.end(), std::mem_fun(&shared_base::method));

Are you trying to implement the Hollywood principle otherwise known as Inversion-of-Control (and also, poorman's error handling)?

Look up both the Observer and Visitor patterns -- they might be of interest.

I whipped something up.

#include <vector>
#include <algorithm>
#include <iostream>

template <typename ARG>
class TaskSystem
{
private:
    class DelegateBase
    {
    public:
        virtual ~DelegateBase() { }
        virtual void Invoke(ARG arg) = 0;
    };

    template <typename T>
    class Delegate : public DelegateBase
    {
    public:
        typedef void (T::*Func)(ARG arg);

    private:
        Func m_func;
        T* m_object;

    public:
        Delegate(T* object, Func func)
            : m_object(object), m_func(func)
        { }

        virtual void Invoke(ARG arg) 
        { 
            ((*m_object).*(m_func))(arg);
        }
    };

    typedef std::vector<DelegateBase*> Delegates;
    Delegates m_delegates;

public:
    ~TaskSystem()
    {
        Clear();
    }

    void Clear()
    {
        Delegates::iterator item = m_delegates.begin();

        for (; item != m_delegates.end(); ++item)
        {
            delete *item;
        }

        m_delegates.clear();
    }

    template <typename T>
    void AddDelegate(T& object, typename Delegate<T>::Func func)
    {
        DelegateBase* delegate = new Delegate<T>(&object, func);
        m_delegates.push_back(delegate);
    }

    void Invoke(ARG arg)
    {
        Delegates::iterator item = m_delegates.begin();

        for (; item != m_delegates.end(); ++item)
        {
            (*item)->Invoke(arg);
        }
    }

};

class TaskObject1
{
public:
    void CallOne(const wchar_t* value)
    {
        std::wcout << L"CallOne(): " << value << std::endl;
    }

    void CallTwo(const wchar_t* value)
    {
        std::wcout << L"CallTwo(): " << value << std::endl;
    }
};

class TaskObject2
{
public:
    void CallThree(const wchar_t* value)
    {
        std::wcout << L"CallThree(): " << value << std::endl;
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    TaskSystem<const wchar_t*> tasks;

    TaskObject1 obj1;
    TaskObject2 obj2;

    tasks.AddDelegate(obj1, &TaskObject1::CallOne);
    tasks.AddDelegate(obj1, &TaskObject1::CallTwo);
    tasks.AddDelegate(obj2, &TaskObject2::CallThree);

    tasks.Invoke(L"Hello, World!\n");

    return 0;
}

Maybe you could think in another way:

for(int i=0; i<task_queue.size(); i++) {
    task_queue[i].method(task_queue[i].object);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top