本来这篇文章应该接着介绍 memset 的,但是我暂时不想写那个主题。这次就写点新的东西。介绍一下 fmt 库。
介绍与安装
{FMT} 是一个开源格式库,按照作者的说法,是提供快速和安全的 替代 C 的 stdio 和 C++ 的iostreams。
项目地址:https://github.com/fmtlib/fmt
下载最新版的 release 文件即可,将 fmt-10.0.0/include/fmt/core.h
include 进来就完成了。其实还可以用 CMake 的,但是今天介绍的重点在语法,所以我就直接单文件 include 了。
据说这个库进入了 C++ 20 当中,不清楚,毕竟我用的还是 C++ 11
用法
最简单的输出就是 print
#define FMT_HEADER_ONLY
#include "fmt-10.0.0/include/fmt/core.h"
int main()
{
fmt::print("Hello fmt!");
}
这样其实和正常的 printf 没有什么区别?C++相对C的最大区别之一就是尽可能地追求typesafe,所以C++从一开始就在寻找替代printf系列函数的解决方案,于是从一开始就有了各种各样的ostream。typesafe是做到了,但是性能低下。三方库 fmt 就是想既解决 typesafe ,也想要一定的性能。
参数替换
类似于 printf 的 % 占位符输出,fmt 使用大括号替代参数。
fmt::print("Also {}","hello fmt!");
输出结果:
Also hello fmt!
其实这种语法有点类似于 Vue.js 的设计。据说是未来的趋势。。。
另一个有效的函数是 fmt::format
,所以上面的输出也可以写成
std::string hello_buffer = fmt::format("Also {}","hello fmt!");
fmt::print("{}",hello_buffer);
另外,和 cout 一样,fmt 输出对参数是无关的。
fmt::println("{}",4.12);
这样的也是可以正常输出的。
参数格式设计
在大括号内可以对格式进行处理,printf
也有类似的功能,但据说 fmt 的功能更加全面?而且 fmt 利用 format
可以直接处理字符串,这点是 printf 没有的。
但是网上针对这个库的文章很少。。。我也是第一次用,所以只能贴出我整理到的用法了。
大括号的参数分为前后两部分,分别为为位置参数(arg_id)和格式化参数(format_spec)。前者用来显式声明参数在字符串中的位置,后者对值进行一定的格式化转换。(这两个是我翻译的,毕竟官网也没有这俩的中文翻译。。。)
位置参数
官方对位置参数的解释是用正则表达式。。。
replacement_field :: = "{"[arg_id][":" format_spec] "}"
arg_id :: = integer | identifier
integer :: = digit +
digit :: = "0"..."9"
identifier :: = id_start id_continue*
id_start :: = "a"..."z" | "A"..."Z" | "_"
id_continue :: = id_start | digit
简单解释下吧
从0开始,然后1、2、3,等等
fmt::println("{0} + {1} = {2}",2,3,5);
//2 + 3 = 5
如果没有指定位置,默认从0往后排
fmt::println("{} + {} = {}",2,3,5);
//2 + 3 = 5
参数位置与值是一一对应的,所以可以交换顺序
fmt::println("{1} + {2} = {0}",5,2,3);
//2 + 3 = 5
如果你不想用数字,也可以用fmt::arg
指定别名参数
fmt::print("Hello, {name}! The answer is {number}. Goodbye, {name}.",
fmt::arg("name", "World"), fmt::arg("number", 42));
//Hello, World! The answer is 42. Goodbye, World.
格式化参数
可选的arg_id放在format_spec的后面,其后是冒号’:'。