C++标准委员会7月科隆会议中投票通过的特性
引言
上周 C++ 标准委员会在科隆举行了7月会议(WG21)。 会议报告请戳:《Trip Report: C++ Standards Meeting in Cologne, July 2019》
会议中重点针对 C++20 标准已经投票通过的特性进行了若干修正,并对一些草案进行了讨论和投票。相比上次会议,通过了一些新的草案。
移除的语言特性
新增的主要语言特性
新增的主要标准库特性
- 文本格式化支持
- C++20 Synchronization Library
- Input Range 适配器
- constexpr std::vector
- constexpr std::string
- 线程可中断 join 支持(Stop Token)
- std::source_location
- 概念(Concepts)采用 C++ 标准库命名规范
- constexpr std::invoke
新增特性介绍
上述特性是本人认为的本次会议投票通过的主要特性。若要浏览全部特性列表,请戳引言中的连接。
下面我将其中一些关键特性作简要介绍。
constinit 关键字
这是新引入的一个关键字,用于强制标记一个全局变量的初始化在编译期完成。若初始化表达式无法在编译期求值,则会引发编译错误。这样便可以避免全局变量的隐式运行时初始化带来的各种各样难以调试的 BUG。
示例:
const char* g() { return "运行时初始化"; } constexpr const char* f(bool p) { return p ? "常量初始化" : g(); } constinit auto c = f(true); // OK constinit auto d = f(false); // 编译错误
using enum
这个特性算是对现有 using
语句用法的一个功能补全。它允许 using 语句运用在 enum
和 enum class
之中。
给出枚举:
// china_railway.hpp enum class china_railway { cr400af, cr400bf, cr200j };
用法1:
using enum china_railway; constexpr auto train_type = cr400af;
用法2:
struct foo { // 引入枚举成员。 using enum china_railway; }; void geek() { foo f; auto a = f.cr400af; // 使用类实例,合法 auto b = foo::cr200j; // 使用类名,合法 }
用法3:
using china_fuxing_trains = china_railway; using rubbish = china_railway::cr200j; // 枚举值别名 constexpr auto type = china_fuxing_trains::cr400bf; constexpr auto fake_emu_train = rubbish; // 和 cr200j 等价
文本格式化支持
这是继模块、协程和概念后又一个重磅特性。它弥补了 C++ 标准库缺乏文本格式化支持的一个遗憾。这次通过的提案基于开源库 fmt,语法十分优雅。文本格式化主要通过两个新的标准库函数 std::format
和 std::format_to
来实现。
示例1:std::format
基本用法
// 自动编号 auto text1 = std::format("{} 是动车组,但 {} 却不是。", "CR400AF", "CR200J"); // 手动编号 auto text2 = std::format("我国领土面积 {0} 万平方公里,人口有 {1} 亿。", 960, 14); // 取消“{}”的转义。 // text3 = "我们的分组是:{100, 200, 300}。" auto text3 = std::format("我们的分组是:{{{0}, {1}, {2}}}。", 100, 200, 300);
示例2:std::format
格式化控制
std::format
函数支持高级格式化控制。它使用格式控制表达式进行格式化输出。标准格式控制表达式的形式如下所示。
"{[arg_index]:[[fill]align][sign]['#']['0'][width]['.' precision][type]}"
看似很复杂的亚子,其实不难,让我们通过如下的表格来解析。
说明:上式中的方括号[]
代表为可选参数。
参数 | 取值 | 说明 |
---|---|---|
arg_id | 参数编号 | 如 0,1,2,... |
fill | 除了 '{' 和 '}' 外的任意字符 | 用于格式填充的字符 |
align | '<', '>', '=', '^' | 控制对齐方式 |
sign | '+', '-', '空格' | 控制正负号显示方式 |
'#' | 控制数值类型输出是否添加前缀 | |
width | 非零整数 或 '{' arg_id '}' | 控制文本长度,若不足将使用 fill 填充 |
precision | 整数 或 '{' arg_id '}' | 控制小数点后的保留的位数 |
type | 'a', 'A', 'b', 'B', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 'p', 's', 'x', 'X' | 控制呈现格式 |
怎么样,是不是通过上表的说明,大家对这个格式控制有了一个初步的理解呢?下面我们继续展开,深入讲讲 align
、sign
和 type
参数取值的具体意义。
表格1: align
参数说明
align | 说明 |
---|---|
'<' | 强制左对齐。若长度不足 width,则从字符串末尾进行填充。 |
'>' | 强制右对齐。若长度不足 width,则从字符串开始进行填充。 |
'=' | 仅用于数值类型。若长度不足 width,则从 sign 或前缀之后、数字开始之前进行填充。 |
'^' | 强制居中对齐。若长度不足 width,则在字符串两侧同时进行填充。 |
表格2: sign
参数说明
sign | 说明 |
---|---|
'+' | 针对正数显式添加 '+' 号,如 "+123"。 |
'-' | 针对负数显式添加 '-' 号,如 "-123";针对正数不添加符号,如 "123"。这是默认选项。 |
'空格' | 针对正数在头部添加一个空格,如 " 123";针对负数添加 '-' 号,如 "-123"。 |
表格3: type
参数说明
type | 说明 | '#' 作用 |
---|---|---|
's' | 按原始字符串输出,仅用于字符串。 | 无 |
'c' | 按原始字符输出,仅用于 char8_t, char16_t, char32_t, char, wchar_t 类型。 | 无 |
'b', 'B' | 按二进制输出,仅用于整数类型,如 "1010"。 | 'b' 添加 "0b"; 'B' 添加 "0B" |
'd' | 按十进制输出,仅用于整数类型,如 "12345"。 | 无 |
'o' | 按八进制输出,仅用于整数类型,如 "10"。 | 添加 "0"。 |
'x', 'X' | 按十六进制输出,仅用于整数类型。'x' 输出小写,'X' 输出大写。 | 'x' 添加 "0x";'X' 添加 "0X" |
'n' | 意义同 'd',但在其基础上,根据本地语言设置,添加十进制的分隔符,如:"1,000,000"。 | 无 |
'a', 'A' | 按十六进制输出,并根据 precision 保留小数,仅用于浮点类型。'a' 输出小写,'A' 输出大写。 | 无 |
'e', 'E' | 按科学计数法输出,仅用于浮点类型。若 precision 省略,则默认为 6。'e' 输出小写,'E' 输出大写。 | 无 |
'f', 'F' | 按十进制输出,并根据 precision 保留小数,仅用于浮点类型。若 precision 省略则默认为 6。'f' 输出小写,'F' 输出大写。 | 无 |
'g', 'G' | 按十进制 + 科学计数法方式输出。若 precision 省略则默认为 6。'g' 输出小写,'G' 输出大写。 | 无 |
'n' | 意义同 'g',但在其基础上,根据本地语言设置,添加十进制的分隔符,如 "1,000.456"。 | 无 |
'p' | 按十六进制输出指针值,仅用于指针类型,如 "FFFFFFFF"。 | 添加 "0x" |
写到这,不得不感叹,这次添加进标准的格式化函数还是非常完备的,考虑到了各种类型的格式化。理论用于实际,让我们看看一些实例吧。
// 高级用法:格式化控制符 char c = 120; auto s0 = std::format("{:6}", 42); // s0 == " 42" auto s1 = std::format("{:6}", 'x'); // s1 == "x " auto s2 = std::format("{:*<6}", 'x'); // s2 == "x*****" auto s3 = std::format("{:*>6}", 'x'); // s3 == "*****x" auto s4 = std::format("{:*^6}", 'x'); // s4 == "**x***" auto s6 = std::format("{:6d}", c); // s6 == " 120" auto s7 = std::format("{:=+06d}", c); // s7 == "+00120" auto s8 = std::format("{:0=#6x}", 0xa); // s8 == "0x000a" auto s9 = std::format("{:6}", true); // s9 == "true "
示例3:std::format_to
的用法
std::format_to
函数主要用于容器类型,如 std::vector<T>
的格式化添加值。
#include <vector> #include <format> #include <string> int main() { std::vector<std::string> data; for (size_t i = 0; i < 100; i++) { std::format_to(std::back_inserter(data), "我的工号是:{} ", i); } }
其中格式字符串的用法等同于 std::format
函数,可参考上述有关内容。
std::source_location
这是一个比较实用的特性。它为标准库新增了一个元数据类 std::source_location
,可为用户提供当前代码的上下文信息。该类的定义如下所示。
namespace std { struct source_location { constexpr source_location() noexcept; constexpr uint_least32_t line() const noexcept; constexpr uint_least32_t column() const noexcept; constexpr const char* file_name() const noexcept; constexpr const char* function_name() const noexcept; static consteval source_location current() noexcept; }; }
示例:
#include <source_location> #include <format> #include <iostream> void foo() { // Get the location of this line. auto loc = std::source_location::current(); std::cout << std::format("Line: {}, Column: {}, Function: {}, File: {}", loc.line(), loc.column(), loc.function_name(), loc.file_name()) << std::endl; }
概念(Concepts)采用标准库命名规范
这个特性是指原本采用 Pascal 命名法的概念,在这次会议中投票通过改为与标准库一致的小写下划线命名法。如:
std::Invocable
改为 std::invocable
std::ConvertibleTo
改为 std::convertible_to
std::EqualityComparable
改为 std::equality_comparable
等等
总结
由于这次投票通过的特性还是比较多的,我只挑选了几个有代表性的展开,其他的就不再一一赘述。(毕竟肉翻还是很费脑细胞的233)。感兴趣的同学可以去看我在引言中的原文链接查阅。由于本人水平有限,若有瑕疵,在所难免。欢迎大家拍砖指正!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
从技术平台到aPaaS平台
互联网行业喜欢搞一些单词的缩写,最近一个朋友换工作,说是去搞aPaaS平台了,那么aPaaS平台是什么呢? 了解下云计算 aPaas是衍生在云平台之上的,如果开发一款应用,需要涉及大量基础技术或者基础设置。 如果从技术层次上划分来说,分为以下几层: application层 data层 runtime层 middleware层 OS层 virtualization层 servers层 storage层 networking层 在以前软件开发及维护过程中需要购买并维护这9层设施,而一些公司可以将这9层基础技术或者基础设施打包起来出售,就是云计算了。 慢慢云计算,云服务就变成了我们服务底层的水电煤,我们每个月交钱就可以了,比自己维护这9层来说简单了很多。 针对这9层的打包方式分为以下几种方式: IaaS:基础即服务 PaaS:平台即服务 SaaS:软件即服务 aPaaS是什么 可以将aPaaS理解为PaaS的一种形式,aPaaS(application Platform as a service,应用程序即服务)。基于aPaaS的解决方案,支持应用程序在云端开发,部署和运行,提供软件开发中...
- 下一篇
Spring5.0源码深度解析之Spring基于注解启动流程分析
主要内容: 一、IOC容器的初始化流 创建IOC容器 注册配置类 BeanFactory后置处理器 Bean的后置处理器 创建Bean对象 IOC容器的初始化流程 从: ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class); 进入: public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) { this(); register(annotatedClasses); refresh(); } 一:创建IOC容器 1.this():先执行父类的初始化方法,创建IOC容器 public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); } 2.执行初始化方法创建BeanDefinition读取器和classPath下扫描器 public...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- CentOS8安装Docker,最新的服务器搭配容器使用
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- 设置Eclipse缩进为4个空格,增强代码规范
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题