递归函数中如何在template上使用operator[]?嵌套vector实现疑问
问题描述
我想要编写代码遍历未知深度的嵌套vector,检查目标索引是否在vector范围内;若不在,则添加空的嵌套vector(同样为未知深度)直至索引可达。
例如,类似{ { { "a" }, { "b" } }, { { "c" } } }的嵌套vector,其数据位于索引[0,0,0]、[0,0,1]和[0,1,0]。若尝试访问索引[0,1,1]并将其设为"d",函数需将vector扩展为{ { { "a"}, { "b" } }, { { "c" }, { "d" } } }。
我计划用template实现该功能,代码如下(为简化未实现赋值逻辑):
template<typename T> void checkVector(T&& vec, vector<int> indexes, int counter = 0) { // Base Case if (counter > int(indexes.size()) - 1) { return; } // Add to vector while (indexes[counter] > int(vec.size()) - 1) { vec.push_back({ {} }); } // Recursive checkVector(vec[indexes[counter]], indexes, counter++); }
但递归部分无法运行,因为在template上使用operator[]会改变类型,导致编译失败。我有两个问题:
- 如何在template中进行索引,并告知编译器该对象同样具备template T的属性?
- 这种实现方式是否可行?
解决方案
问题1的解决思路
你需要区分嵌套vector的中间层和最底层的元素类型,不能用单一模板T处理所有情况。可以通过模板重载实现类型区分:
- 第一个重载专门处理
vector<U>类型(U可以是另一个vector或最终元素类型),负责索引检查、动态扩展和递归调用; - 第二个重载匹配所有非vector类型,作为递归终止条件。
修改后的代码示例:
#include <vector> #include <string> // 处理中间层:vector类型 template<typename U> void checkVector(std::vector<U>& vec, const std::vector<int>& indexes, int counter = 0) { // 遍历完所有索引,终止递归 if (counter >= indexes.size()) { return; } // 扩展vector直到当前索引可达 while (indexes[counter] >= static_cast<int>(vec.size())) { vec.emplace_back(); // 直接构造空的U类型对象(U是vector时即为空vector) } // 递归处理下一层,用counter+1避免post-increment的逻辑错误 checkVector(vec[indexes[counter]], indexes, counter + 1); } // 处理最底层:非vector类型(终止递归) template<typename T> void checkVector(T&, const std::vector<int>&, int) { // 已到叶子节点,无需操作 }
核心要点:
- 用
vector<U>&作为参数,确保编译器只对vector类型执行索引和扩展操作; - 非vector类型的重载自动终止递归,避免类型推断错误;
- 将
indexes改为const引用减少拷贝,用counter+1替代counter++,避免传递自增前的旧值导致逻辑错误。
问题2:实现方式是否可行
你的核心思路(递归遍历+动态扩展vector)是完全可行的,但需要修正原代码中的几个关键问题:
counter++的逻辑错误:post-increment会先传递旧值再自增,导致递归时重复处理同一层,必须改为counter+1;- 模板类型的区分:必须明确区分中间vector层和最终元素层,否则编译器无法正确推断递归类型;
- 边界条件优化:原代码中
counter > int(indexes.size()) -1可以简化为counter >= indexes.size(),逻辑更直观; - 对象构造效率:用
emplace_back()替代push_back({}),直接构造对象而非拷贝临时对象,性能更优。
如果需要添加赋值逻辑,可以调整代码在到达目标索引位置时执行赋值:
template<typename U> void checkAndAssign(std::vector<U>& vec, const std::vector<int>& indexes, const U& value, int counter = 0) { // 到达最后一个索引,执行赋值 if (counter == indexes.size() - 1) { while (indexes[counter] >= static_cast<int>(vec.size())) { vec.emplace_back(); } vec[indexes[counter]] = value; return; } // 扩展当前层vector while (indexes[counter] >= static_cast<int>(vec.size())) { vec.emplace_back(); } // 递归处理下一层 checkAndAssign(vec[indexes[counter]], indexes, value, counter + 1); }
调用示例:checkAndAssign(nested_vec, {0,1,1}, std::string("d")),即可完成你示例中的赋值与扩展操作。
内容的提问来源于stack exchange,提问作者joysterling
相关产品推荐
相关产品推荐

