When multiplexing calls to many sub-objects, what is an elegant way of preventing looping-boilerplate code?
Problem description by example:
struct Foo {
void Boo();
void Hoo();
bool IsActivated();
};
struct FooAggregator {
...
void Boo();
void Hoo();
...
std::vector<Foo> m_foos;
};
FooAggregator::Boo() {
for(size_t i=0, e=m_foos.size(); i!=e; ++i) {
if(m_foos[i].IsActivated()) {
m_foos[i].Boo();
}
}
}
FooAggregator::Hoo() {
for(size_t i=0, e=m_foos.size(); i!=e; ++i) {
if(m_foos[i].IsActivated()) {
m_foos[i].Hoo();
}
}
}
As you can see, the FooAggregator implements the same (similar) interface as a single Foo, iterating over all Foo objects calling their respective member functions.
As you also can see, the iteration loop is complete boilerplate, repeated for every member function of FooAggregator.
What is an elegant way of removing the boilerplate from the implementation of FooAggregators member functions
You could use Boost.Bind
as @Space_C0wb0y suggested. But if you cannot use that for whatever reason, then you can do something of this sort:
struct FooAggregator
{
typedef void (Foo::*Fun)();
void Boo() { CallForEach(m_foos.begin(), m_foos.end(), &Foo::Boo); }
void Hoo() { CallForEach(m_foos.begin(), m_foos.end(), &Foo::Hoo); }
template<typename FwdIterator>
void CallForEach(FwdIterator first, FwdIterator last, Fun fun)
{
while (first != last )
{
if(first->IsActivated())
{
(first->*fun)();
}
first++;
}
}
};
Or you can use std::for_each
from <algorithm>
as:
#include <algorithm>
struct FooAggregator
{
typedef void (Foo::*Fun)();
void Boo() { std::for_each(m_foos.begin(), m_foos.end(), Call(&Foo::Boo)); }
void Hoo() { std::for_each(m_foos.begin(), m_foos.end(), Call(&Foo::Hoo)); }
struct Call
{
Fun m_fun;
Call(Fun fun) : m_fun(fun) {}
void operator()(Foo & foo)
{
if(foo.IsActivated())
{
(foo.*m_fun)();
}
}
};
};
Read about Function object to understand the second example.
In C++0x (i.e C++11), its very simple. You can use lamda in std::for_each
as:
#include <algorithm>
struct FooAggregator
{
void Boo()
{
std::for_each(m_foos.begin(), m_foos.end(), [](Foo &foo){ if (foo.IsActivated()) foo.Boo(); } );
}
void Hoo()
{
std::for_each(m_foos.begin(), m_foos.end(), [](Foo &foo){ if (foo.IsActivated()) foo.Hoo(); } );
}
//other code
};
You could use Boost.Bind to pass a boost::function
object into the dispatching method that specifies which method to call. Then you would only need one dispatch-method that could be called with different target methods as parameter.
I'll take Nawaz's good 1st example and simplify some more:
(Remember, I want to reduce the boilerplate, not introduce the fanciest features.)
// FooAggregator.h
struct FooAggregator {
template<typename MemFn>
void CallForEachFoo(MemFn fun);
void Boo();
void Hoo();
};
// FooAggregator.cpp
template<typename MemFn>
void FooAggregator::CallForEachFoo(MemFn fun) {
BOOST_FOREACH(Foo& o, m_foos) {
if(o.IsActivated()) {
(o.*fun)();
}
}
}
void Boo() { CallForEachFoo(&Foo::Boo); }
void Hoo() { CallForEachFoo(&Foo::Hoo); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With