2009-02-17 5 views
2

Есть ли способ/шаблон/библиотека, чтобы сделать что-то подобное (в псевдокоде):C++ связанных очередей метода (? Менеджер задача/планировщик)

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

так, что я мог сделать что-то как:

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

так, что было бы назвать:

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

Или что невозможный сон?

И если есть способ добавить несколько параметров для вызова - это было бы лучше.

Doug T. см. Это Отличный ответ!

Версия Dave Van den Eynde также хорошо работает.

ответ

5

Да, вы хотели бы объединить boost::bind и boost::functions его очень мощный материал.

Эта версия теперь компилируется благодаря Славе!

#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; 
}; 
+0

Удивительно, но что делать, если у меня есть CClass1 AND CClass2, и в идеале я хотел бы сохранить их обоих? –

+0

Также я думаю, что должен быть _method = _ boost :: bind (AMethod, .... –

+0

Nit: bind копирует свои аргументы по умолчанию, поэтому комментарий «делает instance.AMethod (...)» должен читать «Does * копия * instance.AMethod() " Чтобы действительно вызвать экземпляр, boost :: ref() (или cref) следует использовать для обертывания экземпляра, переданного bind(). –

0

Может быть, вы могли бы думать по-другому:

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

Это означает, что метод task_queue() должен быть перегружен для каждого типа объекта, поэтому очередь задач должна знать о каждом типе объекта. Итак, чтобы добавить новый тип объекта, task_queue необходимо изменить, что плохо. – KeithB

+0

Нет, здесь task_queue [i] - это экземпляр объекта, а не task_queue. Поэтому task_queue [i] .method() вызывает метод, определенный в объекте. Вы не перезаписываете какой-либо метод в task_queue! –

2

Поскольку C++ не поддерживает гетерогенные контейнеры, ваши объекты должны иметь общую базу (так что вы можете уйти с наличием контейнера для указателей на этот базовый класс).

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)); 

Вы пытаетесь реализовать Hollywood principle иначе известный как Inversion из-под контроля (а также обработка ошибок poorman в)?

Посмотрите на модели Observer и Visitor - они могут представлять интерес.

1

Я взбивал что-то.

#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; 
} 
+0

Ничего себе! Это тоже работает, спасибо! Однако ваше умение шаблонов ломает мой мозг :) Удивительно! –

+0

Ну, шаблоны не очень сложно. Это синтаксис указателя функции-члена, который поразил меня, когда я впервые это сделал. –