将容器视为一体
View containers as one
条件是:
// A hierarchy
struct Base {
virtual void everyone_has_this() = 0;
};
struct DA : Base {
void everyone_has_this() override {...}
};
struct DB : Base {
void everyone_has_this() override {...}
void only_db_has_this() {...}
};
// And some vectors
vector<DA> das (3);
vector<DB> dbs (2);
我希望能够使用类似的东西:
// Foreach all of them in one loop
for(Base& o : view_as_one<Base>(das, dbs)) {
o.everyone_has_this();
}
// Or just several types of them
for(DB& o : dbs) {
db.only_db_has_this();
}
问题是:这可能吗
如果不是,那么一个循环的其他方法是什么,而不是每个容器
重要的是,我不想摆脱隔离和存储连续性
如果我使用一个基指针容器,dynamic_cast会起作用,但它需要在每次迭代中检查类型,目标是将所有对象存储在连续存储中。
编辑:如果提升不是选项或视图不足,则可选择其他解决方案
虽然我很喜欢m.s.的解决方案,因为他实现了我想要的接口,但我发现我想要的这个接口实际上并没有那么灵活(不能使用擦除-删除)。所以这里有一个不同的方法:
for_each_in_tuple(std::tie(das, dbs), [](auto& cont){
for(auto& obj : cont) {
// do what you want
}
// or even
cont.erase(std::remove_if(begin(cont), end(cont), [](auto& obj) {
// also do what you want
}, end(cont));
});
- (-)没有那么漂亮
- (+)迭代器不必检查它属于哪个范围(更快)
- (+)即使没有虚拟方法,它也能工作(因为
auto&
) - (+)仅依赖于CCD_ 2=>无升压&编译速度更快
- (+)不受限制(例如,可以使用擦除删除)
- (?)不确定,但看起来msvc2015也可以编译
注意:
有大量的for_each元组算法。我拿了这个:
http://pastebin.com/6e8gmZZA
这可以使用boost::transform_iterator
和boost::join
来实现。
以下代码使用Luc Dantons可变联接实现:
#include <vector>
#include <tuple>
#include <iostream>
#include <utility>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/join.hpp>
#include <boost/range/iterator_range.hpp>
namespace ns {
// for ADL purposes
using std::begin;
using std::end;
struct join_type {
template<class C>
auto operator()(C&& c) const
-> decltype(boost::make_iterator_range(begin(c), end(c)))
{
return boost::make_iterator_range(begin(c), end(c));
}
template<typename First, typename Second, typename... Rest>
auto operator()(First&& first, Second&& second, Rest&&... rest) const
-> decltype( (*this)(boost::join(boost::make_iterator_range(begin(first), end(first)), boost::make_iterator_range(begin(second), end(second))), std::forward<Rest>(rest)...) )
{
return (*this)(boost::join(boost::make_iterator_range(begin(first), end(first)), boost::make_iterator_range(begin(second), end(second))), std::forward<Rest>(rest)...);
}
};
constexpr join_type join {};
} // ns
template <typename T>
struct ReturnTRef
{
T& operator()(T& x) const { return x;};
};
template <typename T, typename Tuple, std::size_t... Indices>
auto view_as_one_impl(Tuple&& tuple, std::index_sequence<Indices...>)
{
ReturnTRef<T> returnTRef;
return ns::join(boost::make_iterator_range(boost::make_transform_iterator(begin(std::get<Indices>(tuple)), returnTRef), boost::make_transform_iterator(end(std::get<Indices>(tuple)), returnTRef))...);
}
template <typename B, typename... Args>
auto view_as_one(Args&&... args)
{
return view_as_one_impl<B>(std::forward_as_tuple<Args...>(args...), std::index_sequence_for<Args...>{});
}
struct Base {virtual ~Base(){}; virtual void talk() = 0;};
struct DA : Base {void talk() override { std::cout << "DA" << std::endl;} };
struct DB : Base {void talk() override { std::cout << "DB" << std::endl;} };
int main()
{
std::vector<DA> das(3);
std::vector<DB> dbs(2);
for(Base& x : view_as_one<Base>(das, dbs))
{
x.talk();
}
}
输出
DA
DA
DA
DB
DB
实例
是的,这是可能的。只需编写一些代码即可。
简单地实现view_as_one
,使其满足C++库容器的要求;或者至少实现该功能所需的最低要求。它的构造函数存储对组成的底层容器的引用。将其iterator
类实现为按顺序对每个组成容器进行迭代。实现view_as_one<T>::begin()
和view_as_one<T>::end()
。完成。
我希望这是一个典型的"高级C++"编程课上的家庭作业。
相关文章:
- 没有找到相关文章