gpt4 book ai didi

c++ - 将容器视为一个容器

转载 作者:行者123 更新时间:2023-11-30 05:24:50 25 4
gpt4 key购买 nike

条件是:

// 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();
}

问题是:这可能吗?
如果不是,还有什么其他方法可以一个循环而不是每个容器?<​​br/>重要的是,我不想摆脱隔离存储连续性。

如果我使用单个基指针容器,dynamic_cast 会起作用,但它会涉及在每次迭代时检查类型,目标是将所有对象存储在连续存储中。


编辑:替代解决方案如果提升不是一个选项或 View 不够
虽然我确实喜欢 m.s. 的解决方案,因为他完全实现了我要求的接口(interface),但我发现我想要的这个接口(interface)实际上并不那么灵活(不能使用删除-删除)。所以这里有一个不同的方法:

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& )。
  • (+) 仅依赖于 <tuple> => 没有提升,编译速度更快。
  • (+) 不受限制(例如可以使用删除-删除)
  • (?) 不确定,但看起来 msvc2015 也可以编译。
    注意:
    有很多 for_each 元组算法。我拿了这个:
    http://pastebin.com/6e8gmZZA

最佳答案

这可以使用 boost::transform_iteratorboost::join 来实现。

以下代码使用 Luc Dantons variadic join实现:

#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

live example

关于c++ - 将容器视为一个容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38542397/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com