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

news2025/1/4 17:18:28

背景

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;
}

运行结果如下:

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/916391.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenEuler 卸载mysql

查询系统是否安装了MySQL rpm -qa | grep -i mysql 关闭mysql 查看MySQL服务运行状态 ps -ef | grep mysql 或者 service mysql status 没有启动 查看rpm包安装的mysql rpm -qa | grep -i mysql 将这些都卸载了 rpm -e mysql5-server rpm -e mysql5-errmsg rpm -e my…

4G WiFi LoRa无线外夹式超声波管道流量计MQTT/http协议 json数据说明

ip&#xff1a;114.128.112.131 port&#xff1a;1883 uname&#xff1a;scwl_flowmeter pwd&#xff1a;b123 topic&#xff1a;iot/data/scwlflowmeter { “deviceId”:“设备序列号”, “flow”:“瞬时流量&#xff08;浮点数&#xff09;”, “heatFlow”:“瞬时热流量&am…

wangzherongyao 2023.08.23

1&#xff09;基本上我都是出制裁&#xff0c;一来够续航&#xff0c;二来死不死都是靠走位&#xff0c;制裁可限制回复英雄以及治疗英雄太多了&#xff1b; 2&#xff09;出个减速冰杖&#xff1b; 3&#xff09;对面威胁大&#xff0c;法师出时之预言&#xff0c;射手出个爆…

wx.request配置服务器域名,只能包含英文大小写字母、数字,解决办法

前言.小程序服务器域名配置常见错误及解决方法 1.配置入口&#xff1a; 小程序后台->-开发->开发设置->服务器域名 2.常见错误及原因分析&#xff1a; 3.实战中出现的错误 4.解决办法&#xff1a;应把域名后边的路径去掉&#xff0c;只写域名即可

【Markdown语法】字体颜色大小及文字底色设置

Markdown字体颜色大小设置 一、更改字体、颜色、大小1、Markdown语法2、一些常用颜色3、文字底色二、some tips1、强调2、放大加粗字体&#xff08;类似于标题&#xff09;3、分割线4、文章转载5、文字加上粉色矩形框附录&#xff1a;颜色列表 一、更改字体、颜色、大小 1、Ma…

翻译:经济周期会持续多久

原文作者&#xff1a; Tejvan Pettinger 时间&#xff1a;4 May 2018 经济周期表明了经济增长如何在不同的阶段波动&#xff0c;例如&#xff1a; 繁荣期&#xff08;通常导致通货膨胀的高经济增长期&#xff09; 峰值期&#xff08;贸易周期的顶点&#xff0c;增长率可能开始…

如何利用Designer自定义SAP采购订单屏幕

Designer介绍&#xff1a; Liquid UI Designer是一个开发工具&#xff0c;它为开发人员提供了图形编辑器和脚本编辑器&#xff0c;对拖放的支持使用户能够创建简化的SAP屏幕和流程。用户无需更改底层ABAP代码和业务逻辑&#xff0c;通过简单的拖拽即可实现屏幕的合并&#xff…

RocketMQ架构

1 RocketMQ的使用场景 ●应用解耦 系统的耦合性越高&#xff0c;容错性就越低。以电商应用为例&#xff0c;用户创建订单后&#xff0c;如果耦合调用库存系统、物流系统、支付系统&#xff0c;任何一个子系统出了故障或者因为升级等原因暂时不可用&#xff0c;都会造成下单操…

Git 原理与使用

1.版本控制器 所谓的版本控制器&#xff0c;就是能让你了解到⼀个⽂件的历史&#xff0c;以及它的发展过程的系统。通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统&#xff0c;同时也⽅便多⼈协同作业。 ⽬前最主流的版本控制器就是 Git 。Git 可以控制电脑…

一文看懂Vision Transformer(VIT)

论文名称&#xff1a; An Image Is Worth 16x16 Words: Transformers For Image Recognition At Scale 论文下载链接&#xff1a;https://arxiv.org/abs/2010.11929 前言 Transformer早在2020年就在NLP领域大放异彩&#xff0c;并通过BERT等无监督预训练技术将NLP推上一个新的…

LAN口 及 WLAN口 配置

目录 1. LAN 口配置 1.设置无线路由器的管理地址 2.配置DHCP服务器 3.无线路由器的状态检查 4.内网预留IP地址 2 .WLAN配置 1.WLAN概述 2.WLAN的部署 3.WLAN的配置 4.配置客户端接入 1. LAN 口配置 1.设置无线路由器的管理地址 选择左边菜单栏中的“基本设置”→“LA…

性能调优篇 一、Jvm监控及诊断工具-命令行篇

目录 一、概述1、简单命令行工具 二、jps&#xff1a;查看正在运行的Java程序1、是什么&#xff1f;2、测试3、基本语法 三、jstat&#xff1a;查看jvm统计信息 一、概述 性能诊断是软件工程师 1、简单命令行工具 二、jps&#xff1a;查看正在运行的Java程序 1、是什么&…

【Android】 No matching variant of com.android.tools.build:gradle:[版本号] was found

项目报错 No matching variant of com.android.tools.build:gradle:8.1.1 was found. The consumer was configured to find a library for use during runtime, compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute …

屏蔽软件,一个技术出生的小企业老板的灵感

我是技术出生&#xff0c;今年开始也带团队了。虽然 人不多&#xff0c;但是有的时候 人在外面出差&#xff0c;不知道办公室的情况。这个时候为了企业的安全考虑&#xff0c;灵感上就想到了开发出一款能屏蔽软件的工具。杜绝掉一些危害公司的一些事。软件后端采用的是JAVA服务…

期权分仓开户资金是否安全?具体保障措施有哪些?

网上关于期权分仓系统的真假一直都没有定论&#xff0c;两方人的争论也让很多没有接触过期权分仓系统的人摸不着头脑&#xff0c;那么期权分仓靠谱吗&#xff1f;资金在里面安全吗&#xff1f;下文为大家科普期权分仓开户资金是否安全?具体保障措施有哪些&#xff1f; 一、期权…

简单易懂的ChatGPT初学者指南-村通网者看

ChatGPT是什么&#xff1f;为什么大家都在关注它&#xff1f;人工智能技术的发展速度超出了预期&#xff0c;这迫使相关的学术机构和企业更新内部通知&#xff0c;以应对AI对工作及工作成果的影响。 OpenAI的推出的ChatGPT利用人工智能与用户进行对话式交流。它不仅可以进行逻辑…

告别繁琐,创造高效率办公!一起了解轻量级的自定义表单开源

在快节奏的社会中&#xff0c;高效率的协作办公成为很多企业的追求目标。什么样的软件平台可以助力实现这一心愿&#xff1f;低代码技术平台拥有多项典型功能&#xff0c;可以满足不同行业的高效率办公需求。自定义表单开源工具轻量级、灵活又易维护&#xff0c;可应用于通信业…

聚观早报|2023戴尔科技峰会助力创新;小米汽车电池供应商敲定

【聚观365】8月23日消息 2023戴尔科技峰会助力企业创新 小米汽车电池供应商敲定中创新航和宁德时代 iPhone15预计有6种配色 王小川卸任自动驾驶企业禾多科技董事 特斯拉动力总成副总裁宣布离职 2023戴尔科技峰会助力企业创新 近日“新生万物 数实新格局 —— 2023戴尔科技…

【TA 挖坑03】雾效 | 透光材质 | Impostor | 厚度转球谐

仍旧是记录下半年想要做的东西&#xff0c;很有趣&#xff0c;实现“一团雾效” “面片也有立体感” 等等效果的一些技术上的方法。 仅粗浅记录&#xff0c;保证之后自己填坑的时候看得懂就行&#xff01; 透光 -> 透光材质ShadingModel 《永劫无间》透光材质的渲染&…

大数据分析案例-基于LightGBM算法构建糖尿病确诊预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…