VS2019 v16.10中头文件更新了

VS2019 v16.10中头文件更新了

作者:BlogUpdater |  时间:2021-06-19 |  浏览:1367 |  评论已关闭 条评论

C++ 20向标准库中添加了一个新型的文本格式化基础设施,主要用来替换传统的snprintf之类的函数,随之带来的是:更快的执行速度和更加安全的接口。C++标准库中的实现是基于现有的{fmt}开源库,所以,使用了这个开源库的用户在迁移到C++标准库之后,会感觉到”回家的感觉”。

在我们深入研究std::format的工作原理之前,我想感谢的你们:Victor Zverovich,Elnar Dakeshov, Casey Carter,以及所有参与贡献的人。正是因为有了你们卓越的工作,我们才得以如此迅速地完成开发。

概述
为了使用,你只需要使用VS2019 v16.10及以上的版本,然后在编译的时候开启/std:c++latest编译开关即可。
最简单的使用的一个例子,如下图所示:

这里的fmt是一个格式化字符串,args是你希望格式化的东西。格式化字符串中可以包含一些由花括号包含的分隔符号。
例如,”Format arguments: {} {}!”就是一个格式化字符串,它用来格式化两个参数。每个占位符对应一个实际传送的参数,所以,让我们猜猜下面语句的输出:
std::format(“Format arguments {} {}!”, 2, 1)

你猜对了,它的输出为:”Format arguments 2 1!”,是不是感觉挺好用的还?

格式化字符串也可以包含数字类型的占位符,举个例子:”Format arguments {1} {0}!”。
这些是指传入的编号参数,从零开始。需要注意的是,编号和未编号(自动)占位符字段不能在同一格式字符串中混合使用。

还可以使用各种修饰符来来修改特定参数的格式化方式。这些被称为”格式修饰符”,并在替换字段中指定,例如:std::format(“{:}”, )。

让我们看实际的例子。

上面这个例子,将会发回字符串:“🐱+1.0000p+2🐱”。(可能将这个字符串打印到Windows控制台窗口会有一点点困难。让我们来一步一步的解析上面的例子。

首先,我们有一个”🐱^”,这时格式化字符串中的一个”填充和对齐”指示符,它的意思是:我希望已居中对齐的方式来输出字符串,并使用一个小猫的表情来作为填充。

接下来,是一个”+”号,意思是:我们希望输出一个符号字符(默认的符号字符是”-“号,它只会在负数的时候输出”-“号,你也可以使用一个空格来添加一个减号或者空格)。

接下来,是一个”#”号,意思是:替代格式。对于浮点数来说,替代格式会导致输出的字符串中总是会添加一个十进制的点。

接下来,我们指定了”12.4″,这样就可以得到一个12个字符的宽度和4个小数位的精度。这意味着,格式化组将将使用前面介绍的填充和对齐设置来确保最终输出为至少12个字符的宽度,并且浮点数拥有4个小数位的精度。

接下来,是一个”L”字母,它的意思是使用用户本地化格式来打印十进制分隔符。

最后,是一个”a”字母,表明输出为浮点类型。

对于宽度和精度指示符,你可以引用一个格式化参数,而不是文本值,如下图所示:

上面的例子会以4个字符宽度和5位小数的精度进行输出。同样,不能混用自动模式和手动索引模式,但是,你可以使用自动索引来引用宽度和精度,如下图所示:

自动索引的赋值是从左到右进行的,所以上面两个例子是等效的。

性能
通常,如果你使用/utf-8编译开关编译代码,则std::format的执行性能应该与fmt::format和 snprintf处于同一范围内。 如果你不使用/utf-8编译开关,那么性能可能会显著 降低,因为我们需要检索当前系统区域设置才能正确地解析格式字符串。虽然我们正在努力在未来版本中提高这种情况下的性能,但我们还是建议开发者使用/utf-8以获得最佳体验。

Unicode
std::format不会在不同的文本编码之间进行任何转码,但是它知道”执行字符集”并使用它来解释格式字符串。
采用宽 (wchar_t) 格式字符串的 std::format 版本总是被解释为 UTF-16。如果我们检测到 /utf-8(或 /execution-charset:utf-8)选项,则采用窄(字符)格式字符串的 std::format 版本会将格式字符串解释为UTF-8。否则,我们将格式字符串解释为在活动系统代码页中编码。

这意味着,如果你使用非 UTF-8 执行字符集编译代码,它可能无法在具有不同系统代码页设置的系统上正确运行。找出系统代码页也有很大的性能成本,因此为了获得最佳性能,就像上面提到的,我们建议使用 /utf-8 进行编译。

在处理字符串的宽度和精度规范时,Unicode也会发挥作用。当我们将格式字符串解释为 UTF-8 或 UTF-16 时,我们会计算字符串的“估算宽度”,同时考虑到每个代码点大小的粗略估计。如果我们将格式字符串解释为非 Unicode 编码,我们只需将宽度估计为字符串中代码单元(而不是代码点)的数量。在未来的版本中,我们将在 Unicode 编码的宽度计算中添加字形聚类。

本地化和语言环境
虽然我们总是根据上述规则解析格式字符串,但可以自定义用于十进制分隔符位置等内容的语言环境。 默认情况下不使用语言环境。 如果你使用”L”指示符,则可能会使用某些特定于语言环境的格式。 默认情况下,它是由默认构造的std::locale返回的当前全局语言环境,但是每个格式化函数都有一个版本,允许你传入自己的 std::locale 对象以覆盖这个行为。

接下来的工作
在接下来的几个 Visual Studio 版本中,我们将改进 std::format 的性能并修复错误。 此外,C++ 23可能会向格式文字添加编译时格式检查,我们可能会在2023年之前实现它。
C++ 23 还将对 std::vformat_to 和 std::format_to 的定义进行小的更改,以减少代码大小,同时,为了向前兼容,请确保任何自定义格式化程序与所有输出迭代器一起使用。 有关这些更改的更多信息,请参考p2216r3。
C++ 23 也可能带来额外的功能,比如 std::print 和更好的方法来处理 Unicode 文本。

实现上的区别
对于那些熟悉 {fmt} 的人,下面列出了它与标准版本库的差异:
> 命名参数尚未被支持。
> 不支持诸如 fmt::print 或 fmt::printf 之类的其他格式化函数。
> 编译时不检查格式字符串。
> 不支持使用 std::ostream& operator<<(std::ostream&, const T&) 重载自动格式化类型。 > 某些格式说明符的行为略有不同(例如 void* 的默认对齐方式,并允许无符号类型的符号说明符)。

总结
你是否还在使用大明湖畔的”printf”?
要不,咱试试老大给我们带来的新玩意儿?

最后
Microsoft Visual C++团队的博客是我非常喜欢的博客之一,里面有很多关于Visual C++的知识和最新开发进展。大浪淘沙,如果你对Visual C++这门古老的技术还是那么感兴趣,则可以经常去他们那(或者我这)逛逛。
本文来自:《format in Visual Studio 2019 version 16.10》

最近我写了个东西
正如你们所知道的,拓扑梅尔智慧办公平台(Topomel Box)是一款绿色软件,主要面向经常使用电脑的朋友。它提供了各种提升办公效率的小功能,同时操作上尽可能地简单方便。
我想:你值得拥有。

标签:

评论已关闭。