Reputation: 6644
I've got a current system of code that works pretty well. I want to make a part of it more efficient.
I've got a class, Foo
, and a ton of subclasses of Foo
that do different things (in this example, I'm using Bar
as the only subclass).
I define how Bar
"updates" during each loop iteration of my main program by declaring a series of step
s in its constructor. This is cool, because I can add multiple step
s that each run for different numbers of iterations.
The problem is that the process of adding a step
to a Bar
is redundant, and I would like to make it less so.
Here's what my class declarations look like:
template <class T>
class Step {
public:
Step();
void (T::*fnPtr)(); // function to execute when step is run within a Foo
int count; // number of iterations to execute on
}
class Foo {
public:
Foo();
void doSomething();
template <class T>
void addStep(Step<T>* newStep) {
// adds a new step to a linked list
}
}
class Bar : public Foo {
public:
Bar();
void doAnotherThing();
void doYetAnotherThing();
void omgAnotherThing();
}
my Bar
constructor would look something like this:
Bar::Bar() {
// ah four lines of code (at least!) every time I want to add a step!
Step<Bar>* a = new Step<Bar>;
a->fnPtr = &Bar::doAnotherThing;
a->count = 10;
addStep(a);
Step<Bar>* b = new Step<Bar>;
b->fnPtr = &Bar::doYetAnotherThing;
b->count = 20;
addStep(b);
Step<Bar>* c = new Step<Bar>;
c->fnPtr = &Bar::omgAnotherThing;
c->count = 6;
addStep(c);
}
Ideally, I'd like the Bar
's step creation look something like this:
Bar::Bar() {
// very nice! I like!
addANewStep(&Bar::doAnotherThing,10);
addANewStep(&Bar::doYetAnotherThing,20);
addANewStep(&Bar::omgAnotherThing,30);
}
But I am not quite sure, in particular, how to pass the &Bar::doAnotherThing
to a function.
Any suggestions?
Upvotes: 1
Views: 120
Reputation: 264411
The easy first Step
is to add a constructor to Step
.
template<typename T>
class Step {
public:
typedef void (T::*Action)();
Step(Action a, int c): action(a), count(c) {}
Action action; // function to execute when step is run within a Foo
int count; // number of iterations to execute on
};
Now your calls are:
addANewStep(new Step(&Bar::doAnotherThing,10));
addANewStep(new Step(&Bar::doYetAnotherThing,20));
addANewStep(new Step(&Bar::omgAnotherThing,30));
Then we notice all the calls to new. With no ownership symantics associated with the resulting pointer. We could add std::unique_ptr<Step>
into the mix. But this class is so simple I think the best solution is to just make the interface take a Step object:
So change I would look at addStep()
template <class T>
void addStep(Step<T>* newStep);
We see you are using pointers because you don't have a homogenous interface (so need the pointers). But the interface is simple so I would still pass as an object and put all the memory management internal to Foo
class (I could alternatively be persuaded that std::unique_ptr<Step<T>>
is an alternative).
template <class T>
void addStep(Step<T> const& newStep) {
pointer_container.push_back(new Step<T>(newStep));
}
This makes your calls look like this:
addANewStep(Step(&Bar::doAnotherThing,10));
addANewStep(Step(&Bar::doYetAnotherThing,20));
addANewStep(Step(&Bar::omgAnotherThing,30));
You now just need to make sure that pointer_container
takes ownership of the pointers.
The next step I would take is look to see if you can replace Step<T>
with std::function<void()>
Upvotes: 0
Reputation: 7473
You may implement addANewStep
method (of Foo
class as I understand) in the following manner:
template <class T>
void addANewStep(void (T::*fnPtr)(), int count)
{
Step<T>* step = new Step<T>;
step->fnPtr = fnPtr;
step->count = count;
addStep(step);
}
And don't forget about semicolon after class definition.
Upvotes: 1
Reputation: 5607
class Foo {
std::vector<
std::pair<std::function<void()>, int>
> m_steps;
public:
Foo();
void doSomething();
template <class F>
void addStep(F callback, int count) {
// add step
m_steps.emplace_back(callback, count);
}
}
Calling the function:
addStep(std::bind(&Bar::doAnotherThing, this), 10);
Passing this
is neccessary so the functor knows on which instance the member function should be called.
Upvotes: 0