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

如何在std::format中读取自定义类型的动态格式选项?

标准合规的std::formatter自定义实现方案(支持自定义Color类型动态参数)

核心思路

利用C++20格式化库的标准参数提取API(std::format_args、std::get)安全获取自定义Color类型的动态参数,完全依赖标准库接口,不依赖任何编译器实现细节。

实现步骤

1. 定义自定义Color类型

enum class Color {
    Red, Green, Blue, Yellow
};

2. 为Color实现基础格式化支持

先让Color本身可被标准格式化库处理,方便后续作为参数提取:

template<>
struct std::formatter<Color> {
    template<typename ParseContext>
    constexpr auto parse(ParseContext& ctx) {
        // Color无需额外格式符,直接返回上下文迭代器
        return ctx.begin();
    }

    template<typename FormatContext>
    auto format(Color c, FormatContext& ctx) {
        const char* color_name = nullptr;
        switch(c) {
            case Color::Red: color_name = "red"; break;
            case Color::Green: color_name = "green"; break;
            case Color::Blue: color_name = "blue"; break;
            case Color::Yellow: color_name = "yellow"; break;
        }
        return std::format_to(ctx.out(), "{}", color_name);
    }
};

3. 实现Text结构体的formatter,支持动态Color参数

核心是在format方法中通过ctx.args()获取格式参数列表,再用std::get提取目标类型参数:

struct Text {
    std::string content;
};

template<>
struct std::formatter<Text> {
    std::optional<Color> static_color; // 存储静态格式符对应的颜色

    template<typename ParseContext>
    constexpr auto parse(ParseContext& ctx) {
        auto it = ctx.begin();
        if (it != ctx.end() && *it == ':') {
            ++it;
            if (it != ctx.end()) {
                switch(*it) {
                    case 'r': static_color = Color::Red; break;
                    case 'g': static_color = Color::Green; break;
                    case 'b': static_color = Color::Blue; break;
                    case 'y': static_color = Color::Yellow; break;
                }
                ++it;
            }
        }
        return it;
    }

    template<typename FormatContext>
    auto format(const Text& txt, FormatContext& ctx) {
        Color target_color = Color::Red; // 默认颜色
        auto args = ctx.args();

        // 优先尝试提取Color类型动态参数
        if (!args.empty()) {
            try {
                target_color = std::get<Color>(args);
            } catch (const std::bad_variant_access&) {
                // 兼容原有int类型参数逻辑
                try {
                    int color_idx = std::get<int>(args);
                    target_color = static_cast<Color>(color_idx);
                } catch (const std::bad_variant_access&) {
                    // 参数类型不匹配,保留默认颜色
                }
            }
        } else if (static_color.has_value()) {
            // 无动态参数时使用静态格式符指定的颜色
            target_color = *static_color;
        }

        // 输出带ANSI颜色的文本(可根据需求替换为其他颜色方案)
        const char* ansi_code = nullptr;
        switch(target_color) {
            case Color::Red: ansi_code = "\033[31m"; break;
            case Color::Green: ansi_code = "\033[32m"; break;
            case Color::Blue: ansi_code = "\033[34m"; break;
            case Color::Yellow: ansi_code = "\033[33m"; break;
        }
        const char* reset_code = "\033[0m";
        return std::format_to(ctx.out(), "{}{}{}", ansi_code, txt.content, reset_code);
    }
};

4. 使用示例

#include <format>
#include <iostream>

int main() {
    // 静态格式符指定颜色
    std::cout << std::format("{:r}", Text{"Hello Red"}) << '\n';
    // 动态int参数指定颜色
    std::cout << std::format("{}", Text{"Hello Green"}, static_cast<int>(Color::Green)) << '\n';
    // 动态Color参数指定颜色
    std::cout << std::format("{}", Text{"Hello Blue"}, Color::Blue) << '\n';
    return 0;
}

关键注意事项

  • 需基于C20或更高版本,因为std::format_args和std::get的相关接口是C20引入的标准特性。
  • 通过try-catch处理类型不匹配的场景,避免程序崩溃,保证代码健壮性。
  • 完全兼容原有静态格式符和int类型动态参数的逻辑,无需修改原有调用代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 02:23:12