You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为std::optional编写支持格式说明符的自定义fmt格式化器

问题:std::optional自定义fmt格式化器无法传递格式说明符导致崩溃

我正在尝试为std::optional编写自定义std::fmt格式化器,当前代码如下:

#include <fmt/core.h>
#include <fmt/ranges.h>
#include <vector>
#include <optional>
#include <cstdint>

template <typename T>
class fmt::formatter<std::optional<T>> {
public:
  constexpr auto parse (format_parse_context& ctx) { return ctx.begin(); }
  template <typename Context>
  constexpr auto format (std::optional<T> const& op, Context& ctx) const {
        if(op) return format_to(ctx.out(), "{}", op.value());
        else return format_to(ctx.out(), "-");
    }
};

int main () {
    std::vector<std::optional<uint64_t>> vec{{1}, {2}, {}};
    fmt::print("{:}\n", vec);
    // fmt::print("{:x}\n", vec);      <----- SIGSEGV
}

当不指定格式说明符时,代码可正常运行,但使用{:x}尝试将uint64_t格式化为十六进制时,会触发段错误,错误信息如下:

Program returned: 139
terminate called after throwing an instance of 'fmt::v6::format_error'
  what():  unknown format specifier
Program terminated with signal: SIGSEGV

解决方案

问题根源在于自定义格式化器没有正确处理格式说明符的传递:你的parse函数直接返回ctx.begin(),未将格式说明符传递给内部T类型的格式化器;同时format函数用硬编码的"{}"格式化值,未利用上下文的格式信息。

正确的做法是让std::optional<T>的格式化器复用T的格式化器逻辑,自动继承T支持的所有格式选项,修改后的代码如下:

#include <fmt/core.h>
#include <fmt/ranges.h>
#include <vector>
#include <optional>
#include <cstdint>

template <typename T>
class fmt::formatter<std::optional<T>> : public fmt::formatter<T> {
public:
  template <typename Context>
  constexpr auto format(const std::optional<T>& op, Context& ctx) const {
    if (op) {
      // 复用T的格式化逻辑,传递当前上下文
      return fmt::formatter<T>::format(*op, ctx);
    } else {
      return fmt::format_to(ctx.out(), "-");
    }
  }
};

int main () {
    std::vector<std::optional<uint64_t>> vec{{1}, {2}, {}};
    fmt::print("{:}\n", vec);
    fmt::print("{:x}\n", vec);  // 现在可正常输出十六进制格式
}

关键说明

  • 继承fmt::formatter<T>:无需手动实现parse函数,格式说明符会被基类正确解析,自动传递给T的格式化逻辑。
  • 调用基类format方法:当optional有值时,直接使用基类的format方法处理内部值,确保{:x}等格式说明符能正确作用于uint64_t。
  • 空值处理:保留原逻辑,用"-"表示空的std::optional。

此修改不仅解决了崩溃问题,还让格式化器兼容所有T类型原本支持的格式化选项,扩展性更强。

内容的提问来源于stack exchange,提问作者Setu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.02 06:14:50