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

如何实现C++20中view::format("{}: {}")的直观语法?

实现直观语法的自定义范围视图:views::format("{}: {}")

需求背景

使用C++20开发,依赖range-v3库处理范围,希望构建自定义范围视图,自动将zip_view等返回的元组传入fmt::format,期望的直观调用语法如下:

std::vector v1{"a",     "b",    "c",     "d"};
std::vector v2{"alpha", "beta", "gamma", "delta"};

fmt::print(
    "", 
    fmt::join(views::zip(v1, v2) | views::format("{}: {}"), "\n")
);

已知可通过views::transform手动提取元组参数传入fmt::format,但希望消除此类样板代码。此前尝试两种方案:

  • 用consteval函数实现时,因非类型模板参数非常量表达式报错;
  • 用字符串字面量模板参数实现了功能,但调用语法views::format2<"{}: {}">()不够直观,目标是实现views::format("{}: {}")的写法。

解决方案

核心思路是利用字符串字面量作为函数参数,通过模板推导捕获编译期常量字符串,结合range-v3的适配器机制实现。具体步骤如下:

1. 定义编译期字符串包装模板

先实现一个能捕获字符串字面量的模板类型,将运行时传入的字面量转为编译期可用的常量:

template <std::size_t N>
struct StringLiteral {
    constexpr StringLiteral(const char (&str)[N]) noexcept {
        std::copy_n(str, N, value);
    }
    char value[N];
};

// 类模板推导指引,自动推导字符串长度
template <std::size_t N>
StringLiteral(const char (&)[N]) -> StringLiteral<N>;

2. 实现format视图适配器

基于range-v3的adaptor_base定义适配器,接受StringLiteral参数并生成对应的transform逻辑:

namespace views {
    namespace detail {
        template <StringLiteral FormatStr>
        struct format_fn {
            template <typename Tuple>
            auto operator()(Tuple&& t) const {
                // 用std::apply自动展开元组参数到fmt::format
                return std::apply(
                    [](auto&&... args) {
                        return fmt::format(FormatStr.value, std::forward<decltype(args)>(args)...);
                    },
                    std::forward<Tuple>(t)
                );
            }
        };

        // 外层适配器,接收字符串字面量并返回绑定格式串的transform视图
        struct format_adaptor : ranges::adaptor_base {
            template <StringLiteral FormatStr>
            constexpr auto operator()() const {
                return ranges::views::transform(format_fn<FormatStr>{});
            }
        };
    }

    // 全局可调用的format视图对象
    inline constexpr detail::format_adaptor format;
}

3. 验证调用语法

现在可以按照期望的直观语法调用:

std::vector v1{"a",     "b",    "c",     "d"};
std::vector v2{"alpha", "beta", "gamma", "delta"};

fmt::print(
    "{}\n", 
    fmt::join(views::zip(v1, v2) | views::format("{}: {}"), "\n")
);
// 输出结果:
// a: alpha
// b: beta
// c: gamma
// d: delta

原理说明

  • StringLiteral模板通过构造函数捕获字符串字面量,借助C++20的类模板推导自动确定字符串长度,将字面量转为编译期常量;
  • format_adaptor的operator()接收StringLiteral参数,返回绑定了对应格式化字符串的transform视图,内部用std::apply自动展开元组参数,彻底消除手动提取元组元素的样板代码;
  • 该方案既保留了fmt库编译期检查格式串与参数匹配的安全性,又实现了简洁直观的函数式调用语法。

注意事项

  • 仅支持传入字符串字面量,若传入运行时生成的字符串会触发编译错误,这符合fmt库编译期校验的设计初衷;
  • 需确保编译环境支持C++20及以上标准,且正确链接range-v3和fmt库。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:15:11