如何使用fmt库控制嵌套容器(如二维vector)的格式与分隔符?
控制fmt库中嵌套容器的分隔符
基础回顾
- 打印普通范围容器:
#include <fmt/ranges.h> std::vector<int> t = {1, 2, 3}; // 输出 "[1, 2, 3]" fmt::print("{}", t);
- 自定义顶层容器的分隔符:
// 输出 "1| 2| 3" fmt::print("{}", fmt::join(t, "| "));
嵌套容器的问题
当处理嵌套容器(如std::vector<std::vector<int>>)时,直接使用fmt::join只能控制顶层元素的分隔符。例如执行以下代码:
std::vector<std::vector<int>> v = {{1,2,3}, {4,5,6}, {7,8,9}}; fmt::print("{}", fmt::join(v, "| "));
会输出 [1, 2, 3]| [4, 5, 6]| [7, 8, 9],无法修改内层容器的默认分隔符。
解决方案
方法1:为内层容器自定义格式化器
通过为特定类型的内层容器定制fmt::formatter,可以修改其默认的分隔符:
#include <fmt/ranges.h> #include <vector> // 为std::vector<int>定制格式化器,指定内层分隔符为"; " template <> struct fmt::formatter<std::vector<int>> : fmt::formatter<fmt::format_string<int>> { template <typename FormatContext> auto format(const std::vector<int>& v, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{}", fmt::join(v, "; ")); } }; int main() { std::vector<std::vector<int>> v = {{1,2,3}, {4,5,6}, {7,8,9}}; // 顶层用" | "分隔,内层用"; "分隔 fmt::print("{}", fmt::join(v, " | ")); // 输出:1; 2; 3 | 4; 5; 6 | 7; 8; 9 }
方法2:递归处理任意深度的嵌套容器
如果需要支持任意层级的嵌套容器,可以编写递归函数来动态控制各层级的分隔符:
#include <fmt/ranges.h> #include <vector> #include <type_traits> // 简化判断:是否为可遍历的范围容器 template <typename T> concept is_range = requires(T t) { std::begin(t); std::end(t); }; // 处理非容器类型的元素 template <typename T> requires (!is_range<T>) void format_element(const T& elem, fmt::format_context& ctx) { fmt::format_to(ctx.out(), "{}", elem); } // 递归处理容器类型,可通过层级参数调整分隔符 template <is_range T> void format_element(const T& range, fmt::format_context& ctx, int level = 0) { auto it = std::begin(range); auto end_it = std::end(range); if (it == end_it) return; format_element(*it, ctx, level + 1); ++it; // 根据当前层级选择分隔符:层级1(顶层)用" | ",层级2(内层)用", " const char* sep = (level == 0) ? " | " : ", "; for (; it != end_it; ++it) { fmt::format_to(ctx.out(), "{}", sep); format_element(*it, ctx, level + 1); } } // 包装函数,返回格式化后的字符串 template <is_range T> std::string format_nested(const T& range) { std::string result; fmt::format_context ctx{result}; format_element(range, ctx); return result; } int main() { std::vector<std::vector<int>> v = {{1,2,3}, {4,5,6}, {7,8,9}}; fmt::print("{}", format_nested(v)); // 输出:1, 2, 3 | 4, 5, 6 | 7, 8, 9 }
这种递归方式可以轻松扩展到更深的嵌套结构,只需调整sep的判断逻辑即可为不同层级设置不同分隔符。
内容的提问来源于stack exchange,提问作者alfC
相关产品推荐
相关产品推荐

