实现多std::vector同索引元素打包时,如何判断各vector大小一致?
需求与问题
我需要实现一个函数,生成一个std::vector,其中每个元素是由传入的多个不同类型std::vector的同索引元素组成的std::tuple。目前的实现能完成基本功能,但有个隐患:如果调用者传入大小不一致的vector,程序会出现越界或逻辑错误。想知道如何判断所有传入的vector大小是否相同。
现有实现代码
template <typename... Args> std::vector<std::tuple<Args...>> Foo(const std::vector<Args>&... vecs) { std::vector<std::tuple<Args...>> result; const auto elems = sizeof...(vecs); std::cout << "Elems = " << elems << std::endl; for (size_t i = 0; i < elems; ++i) { result.emplace_back(std::make_tuple(vecs[i]...)); } return result; } std::vector<int> v1 = {1, 4, 8}; std::vector<double> v2 = {1.1, 4.1, 8.1}; auto vec1 = Foo(v1, v2); // 预期结果:{ {1, 1.1}, {4, 4.1}, {8, 8.1} }
注意:现有代码存在明显bug——循环条件用了
sizeof...(vecs)(传入的vector数量)而非vector实际的元素个数,比如传入2个大小为3的vector时,只会生成2个tuple,而非预期的3个。
解决方法
1. 运行期检查所有vector大小一致
C++17及以上(用折叠表达式简化代码)
先写一个辅助函数判断所有vector大小相同:
template <typename... Args> bool allSameSize(const std::vector<Args>&... vecs) { if (sizeof...(vecs) == 0) return true; const auto targetSize = std::get<0>(std::make_tuple(vecs...)).size(); return ((vecs.size() == targetSize) && ...); }
然后在Foo函数开头加入检查,并修正循环条件:
template <typename... Args> std::vector<std::tuple<Args...>> Foo(const std::vector<Args>&... vecs) { // 检查所有输入vector大小一致 if (!allSameSize(vecs...)) { throw std::invalid_argument("所有传入的vector必须大小相同"); // 调试阶段也可以用assert:assert(allSameSize(vecs...) && "vector大小不一致"); } const auto elemCount = sizeof...(vecs) == 0 ? 0 : std::get<0>(std::make_tuple(vecs...)).size(); std::vector<std::tuple<Args...>> result; result.reserve(elemCount); // 预分配内存提升性能 for (size_t i = 0; i < elemCount; ++i) { result.emplace_back(std::make_tuple(vecs[i]...)); } return result; }
C11/C14兼容版本
如果用较旧的C++标准,递归实现大小检查:
// 空参数时返回true bool allSameSize() { return true; } // 检查第一个vector与后续所有vector大小一致 template <typename T, typename... Rest> bool allSameSize(const std::vector<T>& first, const std::vector<Rest>&... rest) { using std::vector; if (sizeof...(rest) == 0) return true; const auto targetSize = first.size(); // 递归检查后续每个vector bool restCheck = allSameSize(rest...); // 取第一个后续vector的大小和当前比较 const auto firstRestSize = std::get<0>(std::make_tuple(rest...)).size(); return restCheck && (targetSize == firstRestSize); }
2. 编译期检查(仅适用于大小已知的constexpr vector)
如果所有传入的vector大小是编译期常量(比如用constexpr std::vector或std::array),可以在编译期就报错:
template <typename... Args> constexpr bool allSameSize(const std::vector<Args>&... vecs) { if constexpr (sizeof...(vecs) == 0) return true; const auto targetSize = std::get<0>(std::make_tuple(vecs...)).size(); return ((vecs.size() == targetSize) && ...); } template <typename... Args> std::vector<std::tuple<Args...>> Foo(const std::vector<Args>&... vecs) { static_assert(allSameSize(vecs...), "所有vector大小必须相同"); // 后续逻辑同前 }
额外注意事项
- 如果不需要抛出异常,
assert适合调试阶段快速发现问题,但发布版本中assert会被忽略,建议生产环境用异常或返回错误状态。 - 处理空参数的情况:当没有传入任何vector时,返回空vector即可,避免访问空指针。
内容的提问来源于stack exchange,提问作者MKD
相关产品推荐
相关产品推荐

