C++ 好用的格式化库--fmt

2023-11-09

背景

fmt 库是一个开源的 C++ 格式化库,它提供了一种简洁、安全和高效的方式来进行字符串格式化。
该库的设计目标是提供与 Python 的字符串格式化语法类似的功能,同时保持 C++ 的类型安全性和性能。

下载与安装

官网下载

fmt 官网地址:https://fmt.dev/latest/index.html
可以从官网或者 GitHub 存储库 (https://github.com/fmtlib/fmt) 下载源代码并手动构建。

使用 vcpkg 安装

fmt 也可以通过 vcpkg 包管工具进行下载安装:

header-only

fmt 库也支持 header-only 方式使用,需要设置 FMT_HEADER_ONLY 宏。

#define FMT_HEADER_ONLY 
#include "fmt/core.h"

hello world

下面是一个使用C++fmt库的简单示例:

#include "fmt/core.h"

int main()
{
	fmt::print("hello {}", "world");
	return 0;
}

运行上述代码,将输出以下结果:

基本格式化语法

参数替换

类似于 printf 的 % 占位符输出,fmt 使用大括号替代参数,且和参数类型无关:

#include "fmt/core.h"

int main()
{
	fmt::print("hello {}", 123);
	return 0;
}

运行上述代码,将输出以下结果:

按位置替换参数

参数位置默认从 0 开始:

#include "fmt/core.h"

int main()
{
	fmt::print("{0}+{1}={2}", 1,2,3);
	return 0;
}

运行上述代码,将输出以下结果:

如果没有指定位置,默认从 0 往后依次替换:

fmt::print("{}+{}={}", 1,2,3);

运行上述代码,将输出以下结果:

参数格式化

可以要按指定格式替换指定位置的参数,用 {位置:格式} 的形式表示替换内容。

指定填充字符

可以指定字符串长度,若长度不够则使用指定的字符进行填充。

右侧填充

使用 < 表示右填充,即文本居左:

fmt::print("{0:*<10}", "hello");

运行结果如下:

左侧填充

使用 > 表示左填充,即文本居右:

fmt::print("{0:*>10}", "hello");

运行结果如下:

两边填充

使用 ^ 表示在两层填充,即文本居中:

fmt::print("{0:*^10}", "hello");

运行结果如下:

默认填充字符

可以指定填充字符时,默认使用空格进行填充:

fmt::print("{0:>10}\n{1:>10}", "hello","world");

运行结果如下:

动态设置字符串长度

字符串的长度也可以用参数指定:

fmt::print("{0:>{1}}\n{2:>10}", "hello",20,"world");

运行结果如下:

按精度格式化

使用 . 表示精度格式化。

格式化字符串长度

使用 .n 表示把字符串的长度格式为 n :

fmt::print("{0:.4}", "abcdefg");

运行结果如下:

格式化浮点数长度

使用 .n 也可以用来表示把浮点数长度为 n :

fmt::print("{0:.3}", 1.23456);

运行结果如下:

格式化小数位数

使用 .nf 表示把浮点数小数位数格式化为 n:

动态设置精度

精度值也可以通过参数动态设置:

fmt::print("{0:.{1}f}", 3.141596,2);

运行结果如下:

数字正负号格式化

用于格式化数字正负符号显示。

仅负数显示符号

使用 - 表示仅负数显示符号:

fmt::print("正数:{0:}\n负数:{1:}", 30,-20);

运行结果如下:

正负数都显示符号:

使用 + 表示正负数字都显示符号:

fmt::print("正数:{0:+}\n负数:{1:+}", 30,-20);

运行结果如下:

数字进制格式化

格式化为10进制

使用 d 表示格式化数字为10进制进行显示:

fmt::print("10进制:{0:d}", 10);

运行结果如下:

格式化为2进制

使用 b 表示格式化数字为2进制进行显示:

fmt::print("2进制:{0:b}", 10);

运行结果如下:

格式化为16进制

使用 x 表示格式化数字为16进制进行显示:

fmt::print("16进制:{0:x}", 10);

运行结果如下:

显示进制符号

在进制符号前加 # 可以在进制格式化时增加符号标记:

fmt::print("16进制:{0:#x}", 10);

运行结果如下:

格式化数字长度

在进制符号前可以增加长度表示,长度不够补 0 :

fmt::print("{0:08d}", 10);

运行结果如下:

fmt 库使用

格式化内容到字符串

fmt::format 方法会把格式化的结果转为字符串:

#include <iostream>
#include "fmt/core.h"

int main()
{
      auto res = fmt::format("hello {}", "world");
      std::cout << res << std::endl;
      return 0;
}

运行结果如下:

格式化内容到迭代器

fmt::format_to 方法可以把内容格式化到指定的迭代器:

#include "fmt/core.h"

int main()
{
      std::string s;
      fmt::format_to(std::back_inserter(s), "hello {}", "world");
      std::cout << s << std::endl;
      return 0;
}

运行结果如下:

格式化内容到控制台

fmt::print 方法把格式化结果输出到控制台显示:

fmt::print("hello {}", "world");

fmt 库使用进阶

使用参数格式化

命名参数

使用 fmt::arg 可以构建一个命名参数:

fmt::print("{a:*<10}{b:#x}", fmt::arg("a", "hello"), fmt::arg("b", 100));

运行结果如下:

参数列表

fmt::vformat 支持使用参数列表进行格式化:

#include <iostream>
#include "fmt/core.h"

int main()
{
      const fmt::format_args args = fmt::make_format_args(
            fmt::arg("a", "hello"),
            fmt::arg("b", 100)
      );
      const auto s = fmt::vformat("{a:*<10}{b:#x}", args);
      std::cout << s << std::endl;
      return 0;
}

运行结果如下:

同样 fmt::vprint 也支持传入参数列表进行格式化。

自定义类型格式化

特例化 formatter< T > 方式

特例化 fmt::formatter< T > 并且实现其 parse 和 format 方法,可以实现对自定义类型的格式化。

自定义数据类型

使用以下自定义类型作为示例:

struct my_struct
{
      int id;
      std::string name;
};

特例化 fmt::formatter< T >

特例化 fmt::formatter< T > 并实现其 parse 和 format 方法:

template <>
struct fmt::formatter<my_struct>
{
      char presentation = 'f';
      auto parse(fmt::format_parse_context &ctx) -> decltype(ctx.begin())
      {
          auto it = ctx.begin(), end = ctx.end();
          if (it != end && (*it == 'f' || *it == 'i')) presentation = *it++;
          if (it != end && *it != '}') throw "invalid format";
          return it;
      }
      template <typename FormatContext>
      auto format(const my_struct & ms, FormatContext &ctx) const -> decltype(ctx.out())
      {
          return presentation == 'f'
              ? fmt::format_to(ctx.out(), "[my_struct]id={},name= {}", ms.id, ms.name)
              : fmt::format_to(ctx.out(), "[my_struct]id={}", ms.id);
      }
};

使用示例

int main()
{
      my_struct ms{ 0,"hello" };
      fmt::print("my_struct f 格式化:{0:f}\nmy_struct i 格式化:{0:i}", ms);
      return 0;
}

运行结果如下:

继承现有 formatter 类

也可以通过继承现有的 formatter 实现自定义类的格式化:

#include "fmt/core.h"
#include "fmt/format.h"

struct my_struct
{
      int id;
      std::string name;
};
template <>
struct fmt::formatter<my_struct> : formatter<string_view>
{
      auto format(my_struct ms, format_context &ctx) const
      {
            const auto fmt_str = fmt::format("[my_struct]id={}", ms.id);
            const fmt::string_view sv(fmt_str.data(),fmt_str.size());
            return formatter<string_view>::format(sv, ctx);
      }
};
int main()
{
      my_struct ms{ 0,"hello" };
      fmt::print("{}", ms);

      return 0;
}

运行结果如下:

枚举类型格式化

对于枚举类型 fmt 提供了 format_as 接口用于类型转换。

转底层数据类型

使用 fmt::underlying 可以把枚举值转为底层数据类型:

#include "fmt/core.h"
#include "fmt/format.h"

enum class my_enum
{
      red = 0,
      green,
      blue
};
auto format_as(my_enum e)
{
	  return	fmt::underlying(e);
}
int main()
{
      fmt::print("{}", my_enum::green);
      return 0;
}

运行结果如下:

转其他类型

也可以在 format_as 把枚举值转为其他类型:

#include "fmt/core.h"
#include "fmt/format.h"

enum class my_enum
{
      red = 0,
      green,
      blue
};
auto format_as(my_enum e)
{
      switch (e)
      {
      case my_enum::red:
          return "red";
      case my_enum::green:
          return "green";
      case my_enum::blue:
          return "blue";
      }
}
int main()
{
      fmt::print("{}", my_enum::green);
      return 0;
}

运行结果如下:

容器元素格式化

fmt::join 可以定义分隔符对容器中的元素进行格式化:

int main()
{
      std::string s = "1234567";
      fmt::print("{}", fmt::join(s, ", "));
      return 0;
}

运行结果如下:

对于 std::tuple 可以直接进行格式化操作:

#include "fmt/core.h"
#include <fmt/ranges.h>
int main()
{
      std::tuple<int, char> t = { 1, 'a' };
      fmt::print("{}", t);
      return 0;
}

运行结果如下:

微信搜索“编程猿来如此”关注公众号获取更多内容。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 好用的格式化库--fmt 的相关文章

  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • 如何避免情绪低落?

    我有一个实现状态模式每个状态处理从事件队列获取的事件 根据State因此类有一个纯虚方法void handleEvent const Event 事件继承基础Event类 但每个事件都包含其可以是不同类型的数据 例如 int string
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • 在 Visual Studio 2008 上设置预调试事件

    我想在 Visual Studio 中开始调试程序之前运行一个任务 我每次调试程序时都需要运行此任务 因此构建后事件还不够好 我查看了设置的 调试 选项卡 但没有这样的选项 有什么办法可以做到这一点吗 你唯一可以尝试的 IMO 就是尝试Co
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • 将目录压缩为单个文件的方法有哪些

    不知道怎么问 所以我会解释一下情况 我需要存储一些压缩文件 最初的想法是创建一个文件夹并存储所需数量的压缩文件 并创建一个文件来保存有关每个压缩文件的数据 但是 我不被允许创建许多文件 只能有一个 我决定创建一个压缩文件 其中包含有关进一步
  • 如何将图像路径保存到Live Tile的WP8本地文件夹

    我正在更新我的 Windows Phone 应用程序以使用新的 WP8 文件存储 API 本地文件夹 而不是 WP7 API 隔离存储文件 旧的工作方法 这是我如何成功地将图像保存到 共享 ShellContent文件夹使用隔离存储文件方法
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • 如何在 VBA 中声明接受 XlfOper (LPXLOPER) 类型参数的函数?

    我在之前的回答里发现了问题 https stackoverflow com q 19325258 159684一种无需注册即可调用 C xll 中定义的函数的方法 我之前使用 XLW 提供的注册基础结构 并且使用 XlfOper 类型在 V
  • 实体框架 4 DB 优先依赖注入?

    我更喜欢创建自己的数据库 设置索引 唯一约束等 使用 edmx 实体框架设计器 从数据库生成域模型是轻而易举的事 现在我有兴趣使用依赖注入来设置一些存储库 我查看了 StackOverflow 上的一些文章和帖子 似乎重点关注代码优先方法
  • C++ 复制初始化和直接初始化,奇怪的情况

    在继续阅读本文之前 请阅读在 C 中 复制初始化和直接初始化之间有区别吗 https stackoverflow com questions 1051379 is there a difference in c between copy i
  • 控制到达非 void 函数末尾 -wreturn-type

    这是查找四个数字中的最大值的代码 include
  • 如何让Gtk+窗口背景透明?

    我想让 Gtk 窗口的背景透明 以便只有窗口中的小部件可见 我找到了一些教程 http mikehearn wordpress com 2006 03 26 gtk windows with alpha channels https web
  • 将文本叠加在图像背景上并转换为 PDF

    使用 NET 我想以编程方式创建一个 PDF 它仅包含一个背景图像 其上有两个具有不同字体和位置的标签 我已阅读过有关现有 PDF 库的信息 但不知道 如果适用 哪一个对于如此简单的任务来说最简单 有人愿意指导我吗 P D 我不想使用生成的
  • 在 Dynamics CRM 插件中访问电子邮件发件人地址

    我正在编写一个 Dynamics CRM 2011 插件 该插件挂钩到电子邮件实体的更新后事件 阶段 40 pipeline http msdn microsoft com en us library gg327941 aspx 并且在此阶
  • Validation.ErrorTemplate 的 Wpf 动态资源查找

    在我的 App xaml 中 我定义了一个资源Validation ErrorTemplate 这取决于动态BorderBrush资源 我打算定义独特的BorderBrush在我拥有的每个窗口以及窗口内的不同块内
  • mysql-connector-c++ - “get_driver_instance”不是“sql::mysql”的成员

    我是 C 的初学者 我认为学习的唯一方法就是接触一些代码 我正在尝试构建一个连接到 mysql 数据库的程序 我在 Linux 上使用 g 没有想法 我运行 make 这是我的错误 hello cpp 38 error get driver
  • 使用按位运算符相乘

    我想知道如何使用按位运算符将一系列二进制位相乘 但是 我有兴趣这样做来查找二进制值的十进制小数值 这是我正在尝试做的一个例子 假设 1010010 我想使用每个单独的位 以便将其计算为 1 2 1 0 2 2 1 2 3 0 2 4 虽然我
  • 恢复上传文件控制

    我确实阅读了以下帖子 C 暂停 恢复上传 https stackoverflow com questions 1048330 pause resume upload in c 使用 HTTP 恢复上传 https stackoverflow

随机推荐

  • 远程调试(Remote Debugging)

    当运行的程序出现问题时 我们通常通过调试来追踪和定位问题 但是 当运行错误的机器上没有调试工具 我们就需要实现远程调试 简单地说 就是要调试的程序和调试器不在一台机器上 移动端web调试 alert虽然是个土方法 但也是万能的 不过这样会中
  • Javascript与CSS在IE和Firefox中的误区及区别

    Javascript中的常见问题 1 集合类对象问题 现有代码中许多集合类对象取用时使用 IE 能接受 Firefox 不能 解决方法 改用 作为下标运算 如 document forms formName 改为 Js代码 document
  • Vm配置虚拟网络信息&配置虚拟机防火墙&取消软件安装限制&解决问题Temporary failure in name resolution

    目录 配置环境 一 前置知识 1 NAT模式 用的比较多 2 桥接模式 3 仅主机模式 二 修改虚拟网卡信息 1 首先我们可以看到我们这里有两张网卡 问题一 你们可以想一下假如我没有桥接到我的真实可以上网的网卡上会怎么样 这种错误我之前犯过
  • Google敦促更快普及VP9视频压缩技术

    转自 http www cnetnews com cn 2013 0516 2159618 shtml CNET科技资讯网 05月16日 国际报道 计算机行业才谈及VP8解编码技术 Google就希望人们接受它的VP9技术了 Google的
  • DES 密钥生成 加密解密

    import java security InvalidKeyException import java security NoSuchAlgorithmException import java security SecureRandom
  • E1,T1, PRI, Trunk

    E1 T1 PRI Trunk 北美的24路脉码调制PCM简称T1 速率是1 544Mbit s 欧洲的30路脉码调制PCM简称E1 速率是2 048Mbit s 我国采用的是欧洲的E1标准 E1的一个时分复用帧 其长度T 125us 共划
  • read_csv文件读写参数详解————

    python pandas IO tools 之csv文件读写 英文原文 pandas IO tools 读取csv文件 pd read csv 写入csv文件 pd to csv pandas还可以读取一下文件 read csv read
  • .NET诞生20周年 .NET 7有什么新东西?

    首个预览版已发布 NET 7 有什么新东西 随着第一个预览版发布 NET 7 渐渐浮出水面 NET 高级项目经理 Jeremy Likness 在官方博客中介绍了 NET 7 的主要发展方向 俺整理给大伙做一下介绍 NET 7 建立在 NE
  • 实训二十二:交换机标准 ACL 配置

    一 实验目的 1 了解什么是标准的 ACl 2 了解标准 ACL 不同的实现方法 二 应用环境 1 ACL Access Control Lists 是交换机实现的一种数据包过滤机制 通过允许或拒绝特定的数据包进出网络 交换机可以对网络访问
  • Uoj 33 树上GCD (树分治)

    include
  • RabbitMQ:Queue的介绍和使用

    1 声明 当前内容用于本人学习和使用当前的Queue 当前内容为RabbitMQ中对Queue的介绍 当前内容来源 RabbitMQ中的Queue 2 Queue的官方介绍 首先先分析以下前面的Queue的使用 其实这个东西就是一个队列 一
  • Qt项目中头文件无法找到的几个解决办法

    项目场景 在新建项目中引用头文件 问题描述 头文件无法找到 系统提示错误 file not found 原因分析 可能是头文件写错 也可能是路径有问题 解决方案 三种解决方法 1 检查头文件是否写错 注意新旧版本的差异 2 检查路径是否为全
  • Windows下Python加载VLC的方法

    从网上看到一篇文章 Python 流媒体播放器 基于VLC 其中提到windows下开发VLC需要首先安装VLC 否则就需要设置环境变量PYTHON VLC MODULE PATH 但是我尝试了一下 没有成功 但是 这篇文章给了我一个思路
  • 剑指 Offer 25. 合并两个排序的链表

    题目链接 25 合并两个排序的链表 思路分析 利用归并排序的归并思想 Definition for singly linked list struct ListNode int val ListNode next ListNode int
  • 2021中国WMS市场发展趋势和特点

    仓储行业经历了30多年的发展 正在由手工仓向数字仓 智能仓转变 而在这个过程中 作为指挥硬件设备的 大脑 WMS起着不可或缺的作用 WMS系统通过数字化仓库作业过程管控 借助条码化和智能化技术手段 实现仓库作业条码化 作业过程透明化 库存管
  • 【满分】【华为OD机试真题2023 JS】红黑图

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 红黑图 知识点枚举 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 众所周知红黑树是一种平衡树 它最突出的特性就是不能有两个相邻的红色节点 那我们定义一个红黑图
  • shardingsphere引发 java.lang.String cannot be cast to java.lang.Integer异常

    错误描述 mysql数据库查询sql在数据库连接工具中可以正常运行 在加入了shardingsphere的jar包的项目中抛如下异常 java lang ClassCastException java lang String cannot
  • shell脚本循环传值_Shell 脚本的循环控制(for/while/until)

    熟悉其他高级语言的伙伴们肯定了解循环控制语法是编程中非常基础的内容 今天就介绍Shell 中设计循环控制的语法 for while until 等内容 for 命令 for 命令是最简单的循环控制语句 它的格式为 for var in li
  • SyntaxError: Cannot use import statement outside a module

    Node 生态包含两个不同的模块系统 ESM ECMAScript 模块 和 CommonJS 两个模块系统彼此不兼容 其是 SyntaxError 无法在模块外部使用 import 语句 错误 错误 SyntaxError 无法在模块外部
  • C++ 好用的格式化库--fmt

    背景 fmt 库是一个开源的 C 格式化库 它提供了一种简洁 安全和高效的方式来进行字符串格式化 该库的设计目标是提供与 Python 的字符串格式化语法类似的功能 同时保持 C 的类型安全性和性能 下载与安装 官网下载 fmt 官网地址