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

如何实现my_formatter_checker:基于字符串字面量编译期选函数

实现方案

1. 格式字符串检查函数(核心逻辑)

先实现区分fmt风格({})和printf风格(%开头)的检查函数,同时支持编译期字面量和运行时字符串:

编译期检查实现

利用constexpr特性扫描字符串字面量,跳过转义的{{}},判断是否包含有效fmt占位符:

// 核心编译期扫描逻辑
constexpr bool is_fmt_format_string_impl(const char* str) {
    while (*str != '\0') {
        if (*str == '{') {
            // 跳过转义的{{
            if (*(str + 1) == '{') {
                str += 2;
                continue;
            }
            // 找到非转义的{,判定为fmt格式
            return true;
        } else if (*str == '}') {
            // 跳过转义的}}
            if (*(str + 1) == '}') {
                str += 2;
                continue;
            }
        }
        ++str;
    }
    // 未找到fmt占位符,判定为printf格式
    return false;
}

// 匹配编译期字符串字面量(const char[N])
template <size_t N>
constexpr bool my_formatter_checker(const char (&fmt)[N]) {
    return is_fmt_format_string_impl(fmt);
}

// 匹配运行时字符串(const char*),强制走运行时分支
constexpr bool my_formatter_checker(const char* fmt) {
    return false;
}

运行时检查实现

针对运行时生成的字符串,在运行时执行扫描判断:

bool my_formatter_checker_runtime(const char* fmt) {
    while (*fmt != '\0') {
        if (*fmt == '{') {
            if (*(fmt + 1) == '{') {
                fmt += 2;
                continue;
            }
            return true;
        } else if (*fmt == '}') {
            if (*(fmt + 1) == '}') {
                fmt += 2;
                continue;
            }
        }
        ++fmt;
    }
    return false;
}

2. 参数转发的底层函数

针对两种调用形式(带输出目标/不带输出目标)实现重载,根据检查结果转发到对应的fmt库函数:

不带输出目标的版本

#include <fmt/core.h>
#include <fmt/printf.h>
#include <utility>

// 编译期字符串分支:编译期确定调用fmt::print或fmt::printf
template <size_t N, typename... Args>
void print_impl(const char (&fmt)[N], Args&&... args) {
    if constexpr (my_formatter_checker(fmt)) {
        fmt::print(fmt, std::forward<Args>(args)...);
    } else {
        fmt::printf(fmt, std::forward<Args>(args)...);
    }
}

// 运行时字符串分支:运行时检查后选择对应函数
template <typename... Args>
void print_impl(const char* fmt, Args&&... args) {
    if (my_formatter_checker_runtime(fmt)) {
        fmt::print(fmt, std::forward<Args>(args)...);
    } else {
        fmt::printf(fmt, std::forward<Args>(args)...);
    }
}

带输出目标的版本

// 编译期字符串+输出目标分支
template <typename Stream, size_t N, typename... Args>
void print_impl(Stream&& stream, const char (&fmt)[N], Args&&... args) {
    if constexpr (my_formatter_checker(fmt)) {
        fmt::print(std::forward<Stream>(stream), fmt, std::forward<Args>(args)...);
    } else {
        fmt::printf(std::forward<Stream>(stream), fmt, std::forward<Args>(args)...);
    }
}

// 运行时字符串+输出目标分支
template <typename Stream, typename... Args>
void print_impl(Stream&& stream, const char* fmt, Args&&... args) {
    if (my_formatter_checker_runtime(fmt)) {
        fmt::print(std::forward<Stream>(stream), fmt, std::forward<Args>(args)...);
    } else {
        fmt::printf(std::forward<Stream>(stream), fmt, std::forward<Args>(args)...);
    }
}

3. 封装用户调用宏

用宏封装底层函数,保持用户调用方式完全不变:

#define MY_PRINT(...) print_impl(__VA_ARGS__)

验证示例

基础调用场景

int x = some_runtime_func(); // 运行时求值为20
float y = some_runtime_func(); // 运行时求值为10.5

MY_PRINT("{} {}", x, y); // 编译期检测fmt格式,调用fmt::print
MY_PRINT("%d %f", x, y); // 编译期检测printf格式,调用fmt::printf

带输出目标场景

int x = runtime_function(); // 返回20

MY_PRINT(stderr, "{}", x); // 编译期检测fmt格式,输出到stderr
MY_PRINT(stderr, "%d", x); // 编译期检测printf格式,输出到stderr

关键特性说明

  • 编译期安全:字符串字面量的检查完全在编译期完成,无运行时开销,且运行时参数(如x、y)不会在编译期被求值。
  • 自动类型区分:通过模板重载自动识别编译期字符串(const char[N])和运行时字符串(const char*),运行时字符串自动走运行时检查分支。
  • 完全兼容fmt库:支持fmt库的输出目标参数(如stderr、文件流),调用方式与fmt原生接口一致。

内容的提问来源于stack exchange,提问作者Nelsen Edbert Winata

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 21:05:17