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

被折叠的 条评论
为什么被折叠?



