C++格式化库fmt使用方法

1. 格式化库fmt简介

fmt github地址
api说明
格式化参数说明

内容的格式化,体现在代码中主要表现为字符串、基本类型、自定义类型的拼接。例如说打印日志、拼接变量等。C++中我们会经常使用类似printf,snprintf(C风格使用不方便),std::string.append(繁琐), std::iostream(慢)这些来实现格式化。
fmt库是C++语法开发的格式化库,被诸多项目使用。相比于printf,stream主要兼具以下几个优点:

  1. 速度更快,更安全
  2. 支持位置参数
  3. 支持自定义对象的格式化
  4. python风格,更简洁

2. fmt的基本使用

fmt库是python风格的格式化库,语法被{}包裹起来。语法总体上分为两段 {id:format}, id是位置参数或者命名参数,format是具体的格式化说明,包括对齐、宽度、精度、填充等。详细语法说明可以参考: syntax

2.1 基本替换

  • 基本替换
fmt::format("id={},cost={}ms,ret={}", "5d84f51115d6f0d69dc299d280a016a4", 30.0, 0);
// id=5d84f51115d6f0d69dc299d280a016a4,cost=30ms,ret=0
  • 带位置参数的替换
fmt::print("I'd rather be {1} than {0}.\n", "right", "happy");
// I'd rather be happy than right.

2.2 参数格式化

format_spec ::=  [[fill]align][sign]["#"]["0"][width]["." precision]["L"][type]
fill        ::=  <a character other than '{' or '}'>
align       ::=  "<" | ">" | "^"
sign        ::=  "+" | "-" | " "
width       ::=  integer | "{" [arg_id] "}"
precision   ::=  integer | "{" [arg_id] "}"
type        ::=  "a" | "A" | "b" | "B" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" |
                 "o" | "p" | "s" | "x" | "X" | "?"
  • 格式化时间和日期
 auto now = std::chrono::system_clock::now();
  fmt::print("Date and time: {}\n", now);
  fmt::print("Time: {:%H:%M}\n", now);
  • 格式化STL
  std::vector<int> v = {1, 2, 3};
  fmt::print("{::#b}\n", v);
  // [0b1, 0b10, 0b11] 转换成2进制
   std::map<std::string, std::string> kv{{"k1", "v1"}};
  fmt::print("{}", kv);
  // {"k1": "v1"}
  • 对齐、填充、精度、宽度
    例如我要将cost值格式化为小数点后保留3位,总长度为8,不足地方在左侧使用0填充。
    参照上面的语法,fill=0, align=>(选择左对齐),width=8,precision=3,type=f
    fmt::print("cost={0:0>08.3f}\n", 1.2);
  • 整数进制
    例如需要将请求id转换成16进制,固定长度为8位。
    fmt::print("id={:08x}\n", 12567);

2.3 命名参数

使用fmt::arg

  std::string ret = "ret:";
  fmt::format_to(std::back_inserter(ret), "id={}", "123");
  fmt::print("named {ret:}", fmt::arg("ret", ret));

2.4 自定义类型的格式化

实际使用过程中,服务中可能存在一些复杂的结构体,我们希望在日志中打印出该结构体的一些信息便于追踪。例如我们有一个这样的结构体,表示后端服务在处理请求时的一个记录。

struct ServiceContext {
  std::string ip;
  float cost;
  int ret;
  int id;

  std::string ToString() const {
    return fmt::format("[{:08x}] client={}, cost={:.2f}", id, ip, cost);
  }
};

在打印记录的时候我们需要获取该结构体的一些具体信息,通常我们可能会写一个ToString() 或者DebugString()的接口,返回具体的信息。但是有时我们不能直接修改这些结构,也可以在fmt库中位该类型定义format_as接口.

std::string format_as(const ServiceContext &ctx) { 
  return fmt::format("[{:08x}] client={}, cost={:.2f}", ctx.id, ctx.ip, ctx.cost);
}

当然,fmt库也支持为自定义类型定义各种语法,不再深入讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值