在 C++ 中实现呼叫多路复用的优雅方式聚合类?
当多路调用许多子对象时,防止循环样板代码的优雅方法是什么?
问题描述示例:
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 的每个成员函数重复进行。
从 FooAggregators 成员函数的实现中删除样板文件的优雅方法是什么
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以按照@Space_C0wb0y的建议使用
Boost.Bind
。但是,如果您出于某种原因无法使用它,那么您可以执行以下操作:或者您可以使用
中的std::for_each
作为:阅读有关函数对象来理解第二个示例。
在C++0x(即C++11)中,它非常简单。您可以在
std::for_each
中使用 lamda,如下所示: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:Or you can use
std::for_each
from<algorithm>
as: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:您可以使用 Boost.Bind 来传递
boost ::function
对象放入指定调用哪个方法的调度方法中。那么您只需要一种可以使用不同目标方法作为参数来调用的调度方法。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.我将采用 Nawaz 的第一个例子并进一步简化:(
记住,我想减少样板文件,而不是引入最奇特的功能。)
I'll take Nawaz's good 1st example and simplify some more:
(Remember, I want to reduce the boilerplate, not introduce the fanciest features.)
纳瓦兹的回答很有趣,但还有其他解决方案。
首先,您应该认识到您的聚合器在很大程度上是一种
Composite
模式。其次,我会选择 for:
for_each
的成员方法,其中会传递函子(实际上是 2,因为const
重载)。对于外部迭代,请继续阅读:)
相对不幸的是,C++ 迭代器语法并不是真正适合“跳过”迭代器,但它仍然是可以实现的。
然后,您的聚合仅具有
Begin
和End
方法,并且由调用者与您的迭代器交互。注意:您可以将其设置为模板,以便一次性实现可变/常量实现
不过,外部迭代仍然非常庞大,因为 C++ 缺乏使事情变得简单的生成器语法。
Nawaz's answer is interesting, but there are alternative solutions.
First of all, you should recognize that your aggregator is very much a
Composite
pattern.Second of all, I would go either for:
for_each
-like member method to which a functor is passed (2 actually, because of theconst
overload).For external iteration, read on :)
It's relatively unfortunate that C++ iterator syntax is not really geared toward "skipping" iterators, but it is achievable nonetheless.
Then, your aggregate simply has
Begin
andEnd
methods, and it's up to the caller to interact with your iterators.Note: you can make it template to have mutable/const implementations in one go
External iteration remains very bulky though, because C++ lacks a generator syntax to make things simple.