提问人:Damir Tenishev 提问时间:4/10/2023 最后编辑:Damir Tenishev 更新时间:4/12/2023 访问量:183
几乎按顺序连接两个 C++ std::vectors [已关闭]
Virtually sequentially concatenate two C++ std::vectors [closed]
问:
目标是在函数调用时以虚拟方式(这意味着不应发生真正的串联)按顺序连接不同类型的对象的两个 C++ std::vector。
我在不同的向量中有一些类的对象,并希望一些函数将它们作为一个整体进行处理。我不想使用虚函数,动态内存分配既不想将所有不同类型的对象(指向它们的指针)放在同一个容器中,因为在大多数代码中它们都以不同的方式处理,我不会支付额外的价格,也不会为我的类制作复杂的接口。
以下是草稿:
#include <vector>
#include <iostream>
struct A {
void foo() { std::cout << "Hey, I'm A!\n"; }
};
struct B {
void foo() { std::cout << "Hey, I'm B!\n"; }
};
void bar(???) {
???.foo();
}
int main() {
std::vector<A> va(2);
std::vector<B> vb(3);
bar(???);
return 0;
}
当然,我可以逐个处理所有这些向量,但我有很多向量,这会导致代码重复,并在添加新类型时忘记更新此类代码的风险。
更新后来我发现,我真的不需要函数调用时刻的串联,而是动态连接向量的别名,下面接受的答案涵盖了两者。
答:
3赞
SRNissen
4/10/2023
#1
目标是在函数调用时以虚拟方式(这意味着不应发生真正的串联)按顺序连接两个不同类型的对象的 C++。
std::vector
我的理解是,这是不可行的,因为在编译时不可能生成将处理不同类型的对象(在函数中)而不使用动态多态性的代码。
如果所有类型在编译时都是已知的,则可以使用静态多态性来完成 - 当取消引用时,连接视图将返回的不是基础元素,而是包含指向基础类型的指针的对象。std::variant
不过,它不会很优雅。
但是 - 看到您的示例 - 您是否考虑过模板函数方法?如果两者都有方法,你可以A
B
foo
template<typename Vec>
void do_foo(Vec const & vec)
{
for(auto & element : vec)
element.foo()
}
do_foo(va);
do_foo(vb);
现在,如果出现新需求,您无需担心忘记更新其中一个向量的函数,因为它们都是从同一模板中标记的。
评论
0赞
Damir Tenishev
4/10/2023
感谢您的输入。尽管 Evg 的答案更全面,但您的回答帮助我理解我答错了问题。我不能“现在不担心忘记更新函数”,因为我有这个 do_foo(va) 等列表,就我而言,我将有许多数组和许多地方我必须解决这个问题。现在我从 Evg 的答案中看到了如何解决这个问题,我将元组存储为别名。
4赞
Evg
4/10/2023
#2
template<class... Ts>
void bar(Ts&... vecs) {
const auto call_foo_for_each = [](auto& vec) {
for (auto& v : vec)
v.foo();
};
(call_foo_for_each(vecs), ...);
}
void caller() {
bar(va, vb /*, ... */);
}
如果你想把它们作为一个参数传递,你可以把它们打包成一个元组(引用的):
template<class... Ts>
void bar(std::tuple<Ts...> tuple) {
const auto call_foo_for_each = [](auto& vec ) {
for (auto& v : vec)
v.foo();
};
std::apply([&](auto&... vecs) {
(call_foo_for_each(vecs), ...);
}, tuple);
}
void caller() {
bar(std::tie(va, vb /*, ... */));
}
评论
1赞
Evg
4/10/2023
@DamirTenishev 我认为您不能使用标准库缩短此代码。不幸的是,在元编程方面,标准库并没有那么丰富。
1赞
Evg
4/10/2023
@DamirTenishev 即使有了 Boost,我也想不出更短的解决方案。
1赞
Evg
4/10/2023
@DamirTenishev 从文字描述来看,很难说。尝试实现,看看它是否有效。这种方法的主要限制是,在编译时应该知道放入元组的向量。也就是说,您不能在运行时对元组执行类似“push_back”的操作,因为该操作会更改元组类型,而C++不允许这样做。
1赞
Evg
4/10/2023
@DamirTenishev 您的代码是正确的。通常,在使用元组之前,请确保元组所包含的引用不会失效。
1赞
Evg
4/12/2023
@DamirTenishev 很遗憾,如果它是数据成员,则不能使用扣除。.std::tuple
std::tuple<std::vector<A>&, std::vector<B>&> all_objects = std::tie(va, vb);
评论