如何让boost::stacktrace支持fmt::format格式化并解决特化失败问题
问题根因与修复方案
核心错误点
- 误用
fmt::format接口:fmt::format用于直接构造并返回std::string,第一个参数要求是格式字符串,你需要输出到格式上下文的输出迭代器时,应当使用fmt::format_to接口,返回值也刚好匹配formatter的format函数的迭代器返回要求。 - 缺少必要头文件:使用
fmt::join需要引入<fmt/ranges.h>头,否则会找不到对应接口。 - 部分版本的fmt库对于继承
formatter<string_view>但不显式处理parse逻辑的特化会触发编译检查失败,如果不需要自定义格式说明符,直接显式实现空parse逻辑即可。
修复后可运行代码
#include <fmt/core.h> #include <fmt/ranges.h> #include <boost/stacktrace.hpp> using BoostTraceStackFrame = std::remove_reference_t<decltype(boost::stacktrace::stacktrace().as_vector().front())>; template <> struct fmt::formatter<BoostTraceStackFrame> { template <typename ParseContext> constexpr auto parse(ParseContext& ctx) { return ctx.begin(); } template <typename FormatContext> auto format(const BoostTraceStackFrame& rhs, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{}:{}", rhs.source_file(), rhs.source_line()); } }; using BoostTraceType = std::remove_reference_t<decltype(boost::stacktrace::stacktrace())>; template <> struct fmt::formatter<BoostTraceType> { template <typename ParseContext> constexpr auto parse(ParseContext& ctx) { return ctx.begin(); } template <typename FormatContext> auto format(const BoostTraceType& rhs, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "{}", fmt::join(rhs.as_vector(), "\n")); } }; int main() { auto trace = boost::stacktrace::stacktrace(); fmt::print("Foo trace {}", trace); }
可选优化写法
如果需要支持fmt的格式说明符(比如输出宽度、对齐、填充字符等配置),可以继承formatter<string_view>复用其内置的格式解析能力:
template <> struct fmt::formatter<BoostTraceStackFrame> : fmt::formatter<std::string_view> { template <typename FormatContext> auto format(const BoostTraceStackFrame& rhs, FormatContext& ctx) const { std::string frame_info = fmt::format("{}:{}", rhs.source_file(), rhs.source_line()); return fmt::formatter<std::string_view>::format(frame_info, ctx); } };
这种写法不需要自己实现parse函数,基类已经内置了对应逻辑。
内容的提问来源于stack exchange,提问作者Mikhail
相关产品推荐
相关产品推荐

