Mar*_* Ba 6 c++ aggregation multiplexing
当多路调用多个子对象时,什么是阻止循环样板代码的优雅方法?
问题描述示例:
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,FooAggregator实现与单个Foo相同(相似)的接口,迭代调用其各自成员函数的所有Foo对象.
正如您所看到的,迭代循环是完整的样板,为FooAggregator的每个成员函数重复.
从FooAggregators成员函数的实现中删除样板的优雅方法是什么
您可以使用Boost.Bind @ Space_C0wb0y建议.但是如果你出于某种原因不能使用它,那么你可以做这样的事情:
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++;
}
}
};
Run Code Online (Sandbox Code Playgroud)
或者您可以使用std::for_eachfrom <algorithm>:
#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)();
}
}
};
};
Run Code Online (Sandbox Code Playgroud)
阅读有关Function对象的内容以了解第二个示例.
在C++ 0x(即C++ 11)中,它非常简单.您可以使用lamda in std::for_each:
#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
};
Run Code Online (Sandbox Code Playgroud)
我将采用 Nawaz 的第一个例子并进一步简化:
(请记住,我想减少样板文件,而不是介绍最奇特的功能。)
// 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); }
Run Code Online (Sandbox Code Playgroud)