当多路调用多个子对象时,什么是阻止循环样板代码的优雅方法?
问题描述示例:
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(); } } }
如您所见,FooAggregator实现与单个Foo相同(相似)的接口,迭代调用其各自成员函数的所有Foo对象.
正如您所看到的,迭代循环是完整的样板,为FooAggregator的每个成员函数重复.
解决方法
您可以使用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(),&Foo::Hoo); } template<typename FwdIterator> void CallForEach(FwdIterator first,FwdIterator last,Fun fun) { while (first != last ) { if(first->IsActivated()) { (first->*fun)(); } first++; } } };
或者您可以使用< algorithm>中的std :: for_each如:
#include <algorithm> struct FooAggregator { typedef void (Foo::*Fun)(); void Boo() { std::for_each(m_foos.begin(),Call(&Foo::Boo)); } void Hoo() { std::for_each(m_foos.begin(),Call(&Foo::Hoo)); } struct Call { Fun m_fun; Call(Fun fun) : m_fun(fun) {} void operator()(Foo & foo) { if(foo.IsActivated()) { (foo.*m_fun)(); } } }; };
阅读约Function object以了解第二个例子.
在C 0x(即C 11)中,它非常简单.您可以在std :: for_each中使用lamda:
#include <algorithm> struct FooAggregator { void Boo() { std::for_each(m_foos.begin(),[](Foo &foo){ if (foo.IsActivated()) foo.Boo(); } ); } void Hoo() { std::for_each(m_foos.begin(),[](Foo &foo){ if (foo.IsActivated()) foo.Hoo(); } ); } //other code };