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

为自定义类型特化std::formatter编译失败求助(GCC环境)

问题描述

我尝试编译《C++20 STL Cookbook》中为自定义Fraction类型特化std::formatter的示例代码,但在Windows的GCC 13.1环境下出现编译错误,且Compiler Explorer的GCC 13.2环境中也复现了该问题。以下是示例代码及编译错误信息,希望排查程序问题。

示例代码

#include <format>
#include <iostream>

struct Fraction {
    int num;
    int den;
};

template<>
struct std::formatter<Fraction> : std::formatter<int> {
    auto format(Fraction f, format_context& ctx) const {
        return format_to(ctx.out(), "{}/{}", f.num, f.den);
    }
};

int main() {
    Fraction f{3, 4};
    std::cout << std::format("The fraction is {}", f) << '\n';
    return 0;
}

编译错误信息

error: no matching function for call to 'format_to(std::format_context::iterator, const char*, int&, int&)'
   12 |         return format_to(ctx.out(), "{}/{}", f.num, f.den);
      |                ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
问题排查与解决

GCC 13.x对C++20格式化库的实现存在细节差异,导致原代码无法编译,核心问题在于:

  • 继承std::formatter<int>后,直接用format_to传递多参数格式字符串不符合基类的设计预期——基类的format方法仅处理单个int类型的格式化,绑定的上下文无法支持多参数格式化调用。
  • GCC的格式化库实现要求特化的formatter必须正确处理格式解析逻辑,继承基类后复用上下文会触发类型不匹配问题。

修正方案1:从头实现formatter特化(推荐)

放弃继承基类,完整实现std::formatter<Fraction>的解析和格式化逻辑,避免上下文冲突:

#include <format>
#include <iostream>

struct Fraction {
    int num;
    int den;
};

template<>
struct std::formatter<Fraction> {
    // 可选:添加格式解析逻辑,若需支持自定义格式说明符
    constexpr auto parse(std::format_parse_context& ctx) {
        auto it = ctx.begin();
        // 这里可以扩展解析自定义格式,比如限制只能用默认格式
        if (it != ctx.end() && *it != '}') {
            throw std::format_error("Fraction仅支持默认格式");
        }
        return it;
    }

    auto format(const Fraction& f, std::format_context& ctx) const {
        return std::format_to(ctx.out(), "{}/{}", f.num, f.den);
    }
};

int main() {
    Fraction f{3, 4};
    std::cout << std::format("The fraction is {}", f) << '\n';
    return 0;
}

修正方案2:继承基类并正确复用格式化逻辑

如果需要复用std::formatter<int>的格式解析能力(比如支持整数对齐、填充等格式说明符),可以分别调用基类的format方法处理分子和分母:

#include <format>
#include <iostream>

struct Fraction {
    int num;
    int den;
};

template<>
struct std::formatter<Fraction> : std::formatter<int> {
    auto format(const Fraction& f, std::format_context& ctx) const {
        auto out = ctx.out();
        // 复用基类格式化分子
        out = std::formatter<int>::format(f.num, ctx);
        // 添加分隔符
        *out++ = '/';
        // 复用基类格式化分母
        return std::formatter<int>::format(f.den, ctx);
    }
};

int main() {
    Fraction f{3, 4};
    std::cout << std::format("The fraction is {}", f) << '\n';
    // 支持整数格式说明符,比如右对齐5位
    std::cout << std::format("The fraction is {:5}", f) << '\n';
    return 0;
}

验证说明

两种方案都能在GCC 13.1/13.2环境下正常编译运行,第一种方案更灵活,适合自定义格式逻辑;第二种方案适合需要复用已有类型格式化规则的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 09:05:26