如何解析方括号字符串为std::vector并修复模板编译错误
问题描述
需要将逗号分隔的方括号格式字符串解析为std::vector类型,示例预期效果:
- 输入
[1,2,3],解析结果为std::vector<int>{1,2,3} - 输入
[[1,2,3],[4,5,6]],解析结果为std::vector<std::vector<int>> {std::vector<int> {1,2,3}, std::vector<int> {4,5,6}}
尝试通过泛型代码实现该功能时,代码无法通过编译。
初始实现代码
#include <iostream> #include <vector> #include <string> #include <regex> #include <type_traits> #include <algorithm> template<typename Test, template<typename...> class Ref> struct is_specialization : std::false_type {}; template<template<typename...> class Ref, typename... Args> struct is_specialization<Ref<Args...>, Ref> : std::true_type {}; template<typename T, typename UnaryOperation> std::enable_if_t<is_specialization<T, std::vector>::value, T> parse1D(std::string a, UnaryOperation unary_op) { // 一维vector场景:拆分字符串后做类型转换 T ans; if (a.length() < 2 || a[0] != '[' || a[a.length() - 1] != ']') return ans; // 非法格式返回空 std::regex re(","); std::sregex_token_iterator it(a.begin()+1, a.end()-1, re, -1), end; std::transform(it, end, std::back_inserter(ans), unary_op); return ans; } template<typename T, typename UnaryOperation> std::enable_if_t<is_specialization<T,std::vector>::value, T> parse(std::string a, UnaryOperation unary_op) { T ans; if (a.length() < 2 || a[0] != '[' || a[a.length() - 1] != ']') return ans; // 非法格式返回空 if (is_specialization<T::value_type, std::vector>::value) { // 递归处理多维场景 // 未实现递归逻辑 return ans; }else { // 一维vector场景走base case return parse1D<T>(a, unary_op); } }
调用方式与报错
调用代码如下:
auto ret = parse<std::vector<std::vector<int>>>(std::string("[[1,2,3],[4,5,6]]"), [](const auto& el) { return std::stoi(el); });
编译器在std::transform调用位置抛出错误:不存在右操作数为int类型的可用赋值运算符。
错误原因
C++中普通if-else是运行时分支,两个分支的代码都会被编译器实例化编译。即使逻辑上多维vector场景会进入递归分支,else分支调用parse1D<T>的代码依然会被编译:此时T为std::vector<std::vector<int>>,元素类型是std::vector<int>,但传入的转换函数返回int类型,std::transform尝试将int值赋值给vector元素,触发类型不匹配错误。
解决方案
使用C++17引入的if constexpr代替普通if做编译期分支判断:编译器只会实例化符合当前常量条件的分支,直接丢弃不满足条件的分支代码,从根本上避免无效分支的类型错误。
另外原代码中直接按逗号分割的逻辑仅适用于一维vector,多维场景下需要先通过括号计数拆分出每个内层vector的子串,再递归解析,不能直接全局切分逗号。
修正后的完整parse函数实现如下:
template<typename T, typename UnaryOperation> std::enable_if_t<is_specialization<T,std::vector>::value, T> parse(std::string a, UnaryOperation unary_op) { T ans; if (a.length() < 2 || a[0] != '[' || a[a.length() - 1] != ']') return ans; // 非法格式返回空 // 编译期判断:当前vector的元素是否也是vector类型(即是否为多维场景) if constexpr (is_specialization<typename T::value_type, std::vector>::value) { std::vector<std::string> sub_items; int bracket_count = 0; size_t split_start = 1; // 括号匹配计数,拆分出每个内层子vector对应的字符串 for (size_t i = 1; i < a.size() - 1; i++) { if (a[i] == '[') bracket_count++; else if (a[i] == ']') bracket_count--; else if (a[i] == ',' && bracket_count == 0) { sub_items.push_back(a.substr(split_start, i - split_start)); split_start = i + 1; } } sub_items.push_back(a.substr(split_start, a.size() - 1 - split_start)); // 递归解析每个子串 for (auto& sub_str : sub_items) { ans.push_back(parse<typename T::value_type>(sub_str, unary_op)); } return ans; } else { // 一维场景直接调用1D解析逻辑,该分支仅在元素为非vector类型时才会被编译 return parse1D<T>(a, unary_op); } }
内容的提问来源于stack exchange,提问作者HiReaper_
相关产品推荐
相关产品推荐

