如何用fmt库为vector不同元素设置不同样式优雅打印?
用fmt库为std::vector元素设置不同样式并复用标准格式化器
当然可以优雅实现,不用手动遍历或者把格式化后的字符串存进vector里。核心思路是复用fmt内置的range格式化逻辑(比如自动处理逗号分隔、括号包裹),同时为每个元素动态应用样式,下面提供两种简洁的方案:
方案1:使用fmt::join快速实现
fmt::join会帮你处理元素间的逗号分隔,你只需要为每个元素指定样式逻辑,再手动添加前后的括号即可,完全匹配默认的vector输出格式:
#include <vector> #include <fmt/core.h> #include <fmt/ranges.h> #include <fmt/color.h> int main() { std::vector<int> V = {0, 1}; // 用lambda根据索引(或其他条件)给元素设置不同样式 fmt::print("[{}]\n", fmt::join(V, ", ", [index = 0](const auto& val) mutable { auto elem_color = (index++ == 0) ? fmt::color::red : fmt::color::green; return fmt::format(fg(elem_color), "{}", val); })); }
方案2:自定义包装类复用标准格式化器
如果希望语法和默认打印vector完全一致(直接fmt::print("{}", vec)),可以定义一个包装类并特化fmt的formatter,内部复用vector的格式化逻辑,同时注入样式规则:
#include <vector> #include <functional> #include <fmt/core.h> #include <fmt/ranges.h> #include <fmt/color.h> // 包装vector和样式逻辑的结构体 template <typename T> struct StyledVector { const std::vector<T>& data; // 接收元素和索引,返回带样式的格式化参数 std::function<fmt::format_args(const T&, size_t)> style_handler; }; // 为StyledVector特化fmt格式化器 template <typename T> struct fmt::formatter<StyledVector<T>> : fmt::formatter<std::vector<T>> { template <typename FormatContext> auto format(const StyledVector<T>& sv, FormatContext& ctx) const { auto out = ctx.out(); // 复用默认vector的括号格式 *out++ = '['; bool is_first = true; for (size_t idx = 0; idx < sv.data.size(); ++idx) { if (!is_first) { // 复用默认的逗号分隔 out = fmt::format_to(out, ", "); } is_first = false; // 应用自定义样式格式化元素 out = fmt::format_to(out, "{}", sv.style_handler(sv.data[idx], idx)); } *out++ = ']'; return out; } }; int main() { std::vector<int> V = {0, 1}; // 直接像打印普通vector一样使用 fmt::print("{}\n", StyledVector<int>{V, [](const auto& val, size_t idx) { auto color = (idx == 0) ? fmt::color::red : fmt::color::green; return fmt::make_format_args(fg(color), val); }}); }
注意事项
你原来的代码把带ANSI颜色码的字符串存进vector,会导致vector存储的不是原始业务数据,而是格式化后的文本,既丢失了数据语义,也不利于后续的修改和复用。上面的方案都是基于原始数据动态应用样式,更符合代码设计的合理性。
内容的提问来源于stack exchange,提问作者Filippo Bistaffa
相关产品推荐
相关产品推荐

