使用range -v3连接不同的类型



我想知道是否有可能将保存不同类型对象的两个向量连接起来,这样我就可以在连接上迭代并调用公共接口。

像这样:

std::vector<A> as;
as.resize(3);
std::vector<B> bs;
bs.resize(4);
for (const auto &v : ranges::views::concat(as, bs))
{
foo(v);
}

你可以在这里找到一个完整的例子https://godbolt.org/z/nr5hhWMxj

您可以使用views::transform将两个容器中的元素转换为std::variant进行类型擦除。

auto to_variant = ranges::views::transform(
[](auto x) { return std::variant<A, B>(std::move(x)); });
for (const auto& v : ranges::views::concat(as | to_variant, bs | to_variant)) {
std::visit([](const auto& v) { foo(v); }, v);
}

演示

问题很简单:

公共接口是什么?

如果它们有一个共同的类型,比如一个是另一个的后裔,views::concat()就有足够的智能去那里,并且你仍然可以动态调度virtual成员函数。

如果它们都来自相同的基数(但都不是基数),您将能够通过使用views::transform()获得上述结果。

否则,您需要将它们views::transform()到一个可以引用它们的代理对象中,并适当地调度您关心的成员。
虽然std::variant不能,除非您对副本很满意,但std::variant存储std::reference_wrapper可能有效。

auto map = ranges::views::transform([](auto& x) {
return std::variant<std::reference_wrapper<A>, std::reference_wrapper<B>>(std::ref(x)); });
for (const auto& v : ranges::views::concat(as | map, bs | map))
std::visit([](auto x) {
auto& v = x.get();
foo(v);
}, v);

使用static_for_each:

template <class F, class T>
constexpr void static_for_each(F&& f, T&& t) {
std::apply([&](auto&&... x){
((f(std::forward<decltype(x)>(x)), void()), ...);
}, t);
}
static_for_each([&](auto&& c){
for (auto&& v : c)
foo(v);
}, std::forward_as_tuple(as, bs));

最新更新