如何在C++中虚拟拼接不同类型的std::vector以统一处理
问题描述
需要在函数调用期间虚拟拼接两个存储不同类型对象的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; }
解决方案
1. 调用时虚拟拼接:可变参数模板遍历多容器
利用C++11及以上的可变参数模板,实现通用遍历函数,无需实际拼接容器,依次遍历每个传入的容器执行操作,完全在编译期展开,无额外开销。
实现代码
#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() {} // 可变参数模板:遍历当前容器,再递归处理剩余容器 template <typename Container, typename... Rest> void bar(const Container& container, const Rest&... rest) { for (const auto& elem : container) { elem.foo(); } bar(rest...); } int main() { std::vector<A> va(2); std::vector<B> vb(3); bar(va, vb); // 直接传入多容器,虚拟拼接遍历 return 0; }
说明
- 新增类型时,只要元素有
foo()成员函数,直接传入对应容器即可,无需修改bar函数 - 彻底避免重复编写多个容器的遍历逻辑
2. 动态拼接向量别名:轻量级视图类封装
如果需要可复用的"虚拟拼接容器",可以实现一个视图类,持有多个容器的引用,对外提供统一遍历接口,模拟单个容器的行为,无动态内存分配。
实现代码
#include <vector> #include <iostream> #include <tuple> struct A { void foo() { std::cout << "Hey, I'm A!\n"; } }; struct B { void foo() { std::cout << "Hey, I'm B!\n"; } }; // 虚拟拼接视图类,支持任意数量、类型的容器 template <typename... Containers> class JoinedView { private: std::tuple<const Containers&...> containers_; // 递归遍历所有容器执行操作 template <size_t Index = 0> void for_each_impl(auto&& func) const { if constexpr (Index < sizeof...(Containers)) { const auto& container = std::get<Index>(containers_); for (const auto& elem : container) { func(elem); } for_each_impl<Index + 1>(std::forward<decltype(func)>(func)); } } public: explicit JoinedView(const Containers&... containers) : containers_(containers...) {} // 统一遍历接口 void for_each(auto&& func) const { for_each_impl(std::forward<decltype(func)>(func)); } }; // 辅助函数简化视图创建 template <typename... Containers> auto join(const Containers&... containers) { return JoinedView<Containers...>(containers...); } // 使用视图的bar函数 void bar(const auto& joined_view) { joined_view.for_each([](const auto& elem) { elem.foo(); }); } int main() { std::vector<A> va(2); std::vector<B> vb(3); auto joined = join(va, vb); // 创建动态拼接的视图别名 bar(joined); // 视图可复用,还能随时添加更多容器 std::vector<A> va2(1); auto joined2 = join(va, vb, va2); bar(joined2); return 0; }
说明
JoinedView仅持有容器引用,开销极小,符合无动态分配要求- 支持任意数量、类型的容器,只要元素有统一操作接口即可
- 视图可作为"虚拟拼接容器"复用,随时调整包含的容器
内容的提问来源于stack exchange,提问作者Damir Tenishev
相关产品推荐
相关产品推荐

