std::format 总结与分析 附带测试代码

本文详细介绍了C++标准库中的std::format函数的使用方法,包括基本语法、格式化选项、异常处理及如何创建自定义格式化类型。通过多个实例展示了std::format的强大功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

std::format()在这个时间点,2022年,终于让std::cout的可读性比肩printf并且在自定义性和封装性等方面胜过了printf,可以说,std::format就是面向对象的 现代化的 printf
注意:请使用比较新的编译器
本人的编译环境是msvc2022

talk is cheap

#include <format>
#include <string>
#include <vector>
#include <map>

using namespace std;
class StrPair {
public:
	std::pair<std::string, std::string> m_pair;
};
template<>
class formatter<StrPair> {
public:
	/**
	* @brief 解析范围在[context.begin(),context.end())内的格式说明符,将解析格式说明符的结果存在formatter类的数据成员中,返回一个迭代器,指向解析格式说明符字符串结束的下一个字符
	*/	
	constexpr auto parse(auto& context) {
		auto iter{ context.begin() };
		std::cout << "begin=" << *context.begin() << endl;
		//std::cout << "end" << *context.end() << endl;
		std::cout << "end-begin=" << context.end()-context.begin() << endl;
		const auto end{ context.end() };
		if (iter == end || *iter == '}') { //{} format specifier
			m_outputType = OutputType::KeyAndValue;
			return iter;
		}
		switch (*iter) {
		case 'a'://{:a}
			m_outputType = OutputType::KeyOnly;
			break;
		case 'b'://{:b}
			m_outputType = OutputType::ValueOnly;
			break;
		case 'c'://{:c}
			m_outputType = OutputType::KeyAndValue;
			break;
		default://
			throw format_error{ "Invalid KeyValue format specifier." };
			
		}
		++iter;
		if (iter != end && *iter != '}') {
			throw format_error{ "Invalid KeyValue format specifier." };
		}
		std::cout << "return *iter=" << *iter << endl;
		return iter;
	}
	auto format(const StrPair& kv, auto& context) {
		switch (m_outputType)
		{
		case OutputType::KeyOnly:
			return format_to(context.out(), "key:{}", kv.m_pair.first);
		case OutputType::ValueOnly:
			return format_to(context.out(), "value:{}", kv.m_pair.second);
		case OutputType::KeyAndValue:
			return format_to(context.out(), "key:{} value:{}", kv.m_pair.first, kv.m_pair.second);
		default:
			break;
		}
	}
private:
	enum class OutputType {
		KeyOnly,
		ValueOnly,
		KeyAndValue
	};
	OutputType m_outputType{ OutputType::KeyAndValue };
};
int main()
{
	
	cout << format("|hello format|") << endl;//format返回string
	cout << format("|hello {0},how are you {0}|","jalan"s) << endl;//{}起到类似转义占位的作用{0}中可以输入数字代表第几个参数 {}的内容参数可以是:{[index]:[specifier]}
	cout << format("|hello {},how are you {}|", "jalan"s,"computer"s) << endl;//省略index时,index默认从左到右0,1,2....
	cout<< format("|I am fine {{thank you {} }} |","jalan") << endl;//需要大括号显示出来时则需要转义{{代表一个{ }}代表一个} 类似\在printf中的转义
	//下面几种会引起异常抛出 std::format_error
	//cout << format("|hello {0},how are you {}|", "jalan"s, "computer"s) << endl;//混合使用省略index和指定index
	//cout << format("|hello {},how are you {}|", "jalan"s) << endl;//_Args和{}中的index不能严格对应
	
	//specifier 格式说明符
	//一般格式:[[fill]align][sign][#][0][width][.precision][L][type]
	cout << format("|{0:{1}} width hold the door|", "x",10) << endl;//width指定格式化的值所占的最小宽度
	cout << format("|{0:X^{1}} width hold the door|", "x", 10, 'X') << endl;//[[fill]align]中 fill代表用哪个字符填充 
	//align 可选< > ^ 分别代表左对齐,右对齐,居中对齐.未指定width时本项无效 [fill]似乎无法被参数化
	cout << format("|positive {0:+} negative {1:+}|",100,-100) << endl;//sign表示对数字的表示方法. -表示只有负数显示负号 +表示永远显示符号 space表示负数负号,正数空格
	//#启用备用格式 一般和[type] 一起使用 如果一起启用,则会在输出加上0b 0x之类的标识符 b,o,d,x 的大小写会决定#添加的输出的大小写
	//[type]
	//整型
	cout << format("|bin {0:+#10B} {0:+#10b}, oct {1:+#10o} ,dec {2:+#10d} ,hex {3:+#10x} {3:+#10X} |", -128, -128,-128,-128) << endl;
	cout << format("|bin {0:+10B} {0:+10b}, oct {1:+10o} ,dec {2:+10d} ,hex {3:+10x} {3:+10X} |", -1024, -1024, -1024, -1024) << endl;
	//浮点 # 决定打不打. 带#始终打.
	cout << format("|float 指数科学表示法,按照给定精度或者6 {0:+#10e} {0:+#10E} |", 13333333333333.3333333333333333333f)<< endl;
	cout << format("|float 固定表示法,按照给定精度或者6 {0:+#10f} {0:+#10F} |", 13333333333333.3333333333333333333f) << endl;
	cout << format("|float 通用表示法,按照给定精度或者6 {0:+#10g} {0:+#10G} |", 13333333333333.3333333333333333333f) << endl;//default
	cout << format("|float 带有小写a或者大写A的16进制表示法 {0:+#10a} {0:+#10A} |", 13333333333333.3333333333333333333f) << endl;
	cout << format("|float default {0:+#10} {0:+10} |", 13333333333333.0f) << endl;
	//bool s 默认.以文本true false输出之 ,b,c,d,o,x等可以让bool用整型输出
	//char c 默认以字符输出 b,c,d,o,x等可以让char以整形输出
	//string s 默认以字符串输出
	//指针 p 默认 0x为前缀的hex表示法

	//[percision] 只能用于浮点和字符串,表示显示的精度格式为.后跟浮点要输出的小数位数,或者字符串要输出的字符数
	cout << format("|{1:.{2}} {0:+#0.2} {0:+10.2} |", 13333333333333.0f,"show float hhhhhhhhhhhhhh",strlen("show float")) << endl;
	//0 对于数值将0插在数值之前,符号以及任何前缀(如0x)之后,如果设置了对齐则本项无效

	//自定义format 
	//需要实现std::formatter类模板的特化 需要实现一个parse方法和 format方法
	//parse的参数context.begin()实际上停在解析的第一个specifier字符,context.end()是不可解引用的string_view的end,end()-1应该是'}'
	//parse 实际就是解析这段字符串,然后保存一个状态,format根据这个状态去自定义怎么输出.兼容性最好的方式是format_to到context.out()里面.也就是调用format的那个out里.
	StrPair sp;
	sp.m_pair={ "1","2" };
	cout << std::format("{0:a}",sp) << endl;
	cout << std::format("{0:b}", sp) << endl;
	cout << std::format("{0:c}", sp) << endl;
	return 0;
}

输出

|hello format|
|hello jalan,how are you jalan|
|hello jalan,how are you computer|
|I am fine {thank you jalan } |
|x          width hold the door|
|XXXXxXXXXX width hold the door|
|positive +100 negative -100|
|bin -0B10000000 -0b10000000, oct      -0200 ,dec       -128 ,hex      -0x80      -0X80 |
|bin -10000000000 -10000000000, oct      -2000 ,dec      -1024 ,hex       -400       -400 |
|float 指数科学表示法,按照给定精度或者6 +1.333333e+13 +1.333333E+13 |
|float 固定表示法,按照给定精度或者6 +13333333803008.000000 +13333333803008.000000 |
|float 通用表示法,按照给定精度或者6 +1.33333e+13 +1.33333E+13 |
|float 带有小写a或者大写A的16进制表示法 +1.840d14p+43 +1.840D14P+43 |
|float default          +1.3333334e+13 +1.3333334e+13 |
|show float +1.3e+13   +1.3e+13 |
begin=a
end-begin=2
return *iter=}
key:1
begin=b
end-begin=2
return *iter=}
value:2
begin=c
end-begin=2
return *iter=}
key:1 value:2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值