Reputation: 716
I have a class called "Tasks" that needs to store methods from other classes, and be able to execute them. I'd like it to work like this:
Window *window = new Window();
Tasks* tasks = new Tasks();
tasks.m_tasks.Add(window.Create("My Window"));
Then I could call that window creation from my tasks class, by iterating over the stored tasks and executing each one:
tasks.ExecuteTasks();
What would be the datastructure of "m_tasks" that stores the functions, and how could I call them?
Upvotes: 3
Views: 262
Reputation: 13521
You could use a list of tr1 or boost ::functions as @aschepler says, but this scenario is perfect for boost::signals.
class Tasks {
boost::signal<void ()> m_tasks;
};
// ...
tasks.m_tasks.connect(&someFunction);
// ExecuteTasks:
tasks.m_tasks();
This allows for a lot of extra functionality, like handling arguments, returns, and letting clients disconnect their tasks if they want to.
Upvotes: 1
Reputation: 72311
I would use a std::list<std::function<void()> >
, or boost::function
if std::function
is not available.
And you'll need to change the syntax of that Add
call to avoid executing the Create
method right away.
C++11:
class Tasks {
public:
void Add(const std::function<void()>& f)
{ callbacks_.push_back( f ); }
void Add(std::function<void()>&& f)
{ callbacks_.emplace_back( std::move( f ) ); }
// ...
private:
std::list<std::function<void()> > callbacks_;
};
int main() {
Window window;
// ...
tasks.Add( [&]() { window.Create("My Window"); } );
// ...
}
C++03:
class Tasks {
public:
void Add(const boost::function<void()>& f)
{ callbacks_.push_back( f ); }
private:
std::list<boost::function<void()> > callbacks_;
};
int main() {
// ...
tasks.Add( boost::bind( &Window::Create, boost::ref(window), "My Window" ) );
// ...
}
Upvotes: 4
Reputation: 3351
m_tasks is going to be a collection of some sort, I'd probably use a list unless you need to be able to add/remove in the middle. The thing you will be storing in the list is a function pointer. That is, a pointer to a function. With the straightforward version of the code I have below, you cannot have generic function pointers, you must be specific about the parameter types and the return value type. It might be possible to use templates to break this restriction. I don't know off the top of my head.
// define FunctionPtr as a pointer to a function that takes a single char* param and returns void
typedef void(*FunctionPtr)(char*);
// define an stl:list of FunctionPtr items
std:list<FunctionPtr> m_tasks;
Upvotes: 0
Reputation: 8647
This is relatively straightforward if you know what the arguments will be. You could use a function pointer, with some extras to make it a 'method' pointer. See:
However, this would not allow you to pass arbitrary arguments. You might be able to do it with C++ templates, but it would be nasty hackery. I would strongly advise avoiding this and going with traditional function/method pointers if at all possible.
Upvotes: 0
Reputation: 1207
You'll need slightly complicated structure for this:
class Task
{
public:
virtual void Execute()=0;
};
template<class T, class R, class P1>
class Function1 : public Task
{
public:
Function1(T *ptr, R (T::*fptr)(P1), P1 p1) : ptr(ptr), fptr(fptr),p1(p1) { }
void Execute() { (ptr->*fptr)(p1); }
private:
T *ptr;
R (T::*fptr)(P1);
P1 p1;
};
std::vector<Task*> vec;
Upvotes: 0