ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

fmt 运行时格式字符串如何用 fmt::runtime 包装并通过类型安全检查

fmt 运行时格式字符串如何用 fmt::runtime 包装并通过类型安全检查 fmt 运行时格式字符串如何用 fmt::runtime 包装并通过类型安全检查【免费下载链接】fmtA modern formatting library项目地址: https://gitcode.com/GitHub_Trending/fm/fmt在 {fmt} 中格式字符串默认参与类型安全检查字符串字面量在 C20编译器支持consteval下于编译期检查格式说明符与参数类型不匹配时直接编译失败。但格式字符串有时无法在编译期确定——比如运行时拼接出来的 chrono 说明符、配置里读出的模板串——这类值不能直接传给fmt::format等接受format_stringT...的函数。{fmt} 为此提供了fmt::runtime把运行时字符串包装成runtime_format_string让同一组类型安全 API 接受它检查从编译期推迟到运行期不匹配时抛出fmt::format_error。本文基于 doc/api.md 与头文件中的定义给出包装方式和验证手段。为什么运行时字符串需要包装doc/api.md 对格式参数的定义是fmt::format_string是从字符串字面量或constexpr字符串隐式构造、并在 C20 下做编译期检查的格式字符串而 “To pass a runtime format string wrap it infmt::runtime”。fmt::runtime的定义在 include/fmt/core.htemplate typename Char char struct runtime_format_string { basic_string_viewChar str; }; /** * Creates a runtime format string. * * **Example**: * * // Check format string at runtime instead of compile-time. * fmt::print(fmt::runtime({:d}), I am not a number); */ inline auto runtime(string_view s) - runtime_format_string { return {{s}}; }包装之所以可行是因为fstringformat_stringT...的底层类型专门提供了从runtime_format_string构造的入口见 include/fmt/core.h 的fstring(runtime_format_string fmt) : str(fmt.str) {}。也就是说fmt::runtime(s)是运行时字符串进入这套 API 的唯一通道不包装的普通string_view/std::string无法通过format_string参数的类型推导。使用 fmt::runtime 的完整示例下面的程序演示两条路径运行时拼接出的格式字符串被正常格式化类型不匹配的运行时字符串在运行期抛出fmt::format_error并被捕获。{:d}与fmt::print的组合直接取自 core.h 中的文档示例#include fmt/core.h #include string int main() { // 1. 运行时构造的格式字符串拼好之后用 fmt::runtime 包装再传入 std::string spec {:; // 等价于测试代码中的拼接方式 for (int i 0; i 30; i) spec %c; spec }\n; fmt::print(fmt::runtime(spec), *std::localtime(nullptr)); // 2. 文档示例格式说明符与参数类型不匹配 // 检查发生在运行时抛出 fmt::format_error try { fmt::print(fmt::runtime({:d}), I am not a number); } catch (const fmt::format_error e) { std::printf(caught: %s\n, e.what()); } }编译前提与文档一致在支持 C20consteval的编译器下编译时字符串字面量走编译期检查fmt::runtime包装的值走运行期检查。第二段在文档语义下预期被catch捕获文档只标注了这是 “Check format string at runtime instead of compile-time” 的例子没有给出固定输出所以不要按某个确定文案判断成败判断依据是“异常被捕获、程序未崩溃”。运行期检查会报哪些错fmt::format_error继承自std::runtime_error见 include/fmt/format.hcore.h 中report_error的注释明确了两种时机编译期报错或通过format_error异常在运行期报错。仓库测试套件对运行期错误消息有具体断言可作为核对依据以下消息来自 test/format-test.cc 的runtime_precision测试括号不闭合或说明符非法invalid format string动态宽度/精度引用了不存在的参数argument not found负数或超大宽度/精度width/precision is out of range说明符与参数类型不匹配例如 test/format-test.cc 中断言fmt::format(fmt::runtime({:x}), std::string(test))抛出fmt::format_error这些测试同时是验证方式如果你的调用链与上述用例同形fmt::runtime包装 不匹配参数应观察到fmt::format_error异常而不是未定义行为或静默输出。非 C20 编译器的替代检查方式当编译器不支持 C20consteval时doc/api.md 的 “Compile-Time Checks” 与 “Legacy Compile-Time Checks” 给出替代路径FMT_STRING宏在旧编译器上启用编译期检查要求 C14 或更高在 C11 下是无操作no-op。预定义FMT_ENFORCE_COMPILE_STRING可强制使用旧式检查此时接受FMT_STRING的函数遇到普通字符串会编译失败避免绕过检查。这两者与fmt::runtime的关系是FMT_STRING/字面量负责“能编译期查就编译期查”fmt::runtime负责“确实只能运行期查”的字符串。宽字符场景下fmt/xchar.h提供了对应重载inline auto runtime(wstring_view s) - runtime_format_stringwchar_t见 include/fmt/xchar.h用法与char版本一致。为自定义函数保留类型安全检查如果自己在写接受格式字符串的函数如日志不要直接声明void log(std::string_view fmt, ...)了事——那会丢掉全部检查。doc/api.md 的 “Type Erasure” 一节给出的标准模式是双层结构非模板底层接收string_viewformat_args模板顶层接收fmt::format_stringT...检查发生在顶层模板实例化时#include fmt/format.h void vlog(const char* file, int line, fmt::string_view fmt, fmt::format_args args) { fmt::print({}: {}: {}, file, line, fmt::vformat(fmt, args)); } template typename... T void log(const char* file, int line, fmt::format_stringT... fmt, T... args) { vlog(file, line, fmt, fmt::make_format_args(args...)); } #define MY_LOG(fmt, ...) log(__FILE__, __LINE__, fmt, __VA_ARGS__) MY_LOG(invalid squishiness: {}, 42);文档指出vlog不按参数类型模板化相比完全模板化的版本能改善编译时间并减小二进制体积。若格式字符串在调用方是运行期值如配置读入调用侧再按前文方式用fmt::runtime包装。验证清单与限制按以下顺序自证整条路径可用编译期把{:d}字面量直接配一个非整型参数传入fmt::print不加fmt::runtime在 C20 下应得到编译错误——fstring构造注释写明 “Reports a compile-time error if S is not a valid format string for T”。运行期对fmt::runtime({:d})配非整型参数应抛出fmt::format_error可用catch (const fmt::format_error)捕获验证。可用路径运行时拼接的合法字符串如上文{:%ccc...}式 chrono 说明符包装后正常输出参考 test/chrono-test.cc 的grow_buffer用例构造方式。需要记住的边界fmt::runtime只是把检查推迟到运行期运行期不匹配仍是异常不是降级为无检查编译期检查默认在支持 C20consteval的编译器上开启旧编译器依赖FMT_STRINGC11 下该宏无效更多格式语法细节见 doc/syntax.md接入与构建方式CMake 目标、包管理器见 doc/get-started.md。【免费下载链接】fmtA modern formatting library项目地址: https://gitcode.com/GitHub_Trending/fm/fmt创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表