CppGuide社区 CppGuide社区
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
GitHub (opens new window)
首页
  • 最新谷歌C++风格指南(含C++17/20)
  • C++17详解
  • C++20完全指南
  • C++23快速入门
  • C++语言面试问题集锦
  • 🔥C/C++后端开发常见面试题解析 (opens new window)
  • 网络编程面试题 (opens new window)
  • 网络编程面试题 答案详解 (opens new window)
  • 聊聊WebServer作面试项目那些事儿 (opens new window)
  • 字节跳动面试官现身说 (opens new window)
  • 技术简历指南 (opens new window)
  • 🔥交易系统开发岗位求职与面试指南 (opens new window)
  • 第1章 高频C++11重难点知识解析
  • 第2章 Linux GDB高级调试指南
  • 第3章 C++多线程编程从入门到进阶
  • 第4章 C++网络编程重难点解析
  • 第5章 网络通信故障排查常用命令
  • 第6章 高性能网络通信协议设计精要
  • 第7章 高性能服务结构设计
  • 第8章 Redis网络通信模块源码分析
  • 第9章 后端服务重要模块设计探索
  • 🚀 全部章节.pdf 下载 (opens new window)
  • 源码分析系列

    • leveldb源码分析
    • libevent源码分析
    • Memcached源码分析
    • TeamTalk源码分析
    • 优质源码分享 (opens new window)
    • 🔥远程控制软件gh0st源码分析
  • 从零手写C++项目系列

    • C++游戏编程入门(零基础学C++)
    • 🔥使用C++17从零开发一个调试器 (opens new window)
    • 🔥使用C++20从零构建一个完整的低延迟交易系统 (opens new window)
    • 🔥使用C++从零写一个C语言编译器 (opens new window)
    • 从零用C语言写一个Redis
  • Windows 10系统编程
  • 🔥Linux 5.x内核开发与调试 完全指南 (opens new window)
  • TCP源码实现超详细注释版.pdf (opens new window)
  • Go语言特性

    • Go开发实用指南
    • Go系统接口编程
    • 高效Go并发编程
    • Go性能调优
    • Go项目架构设计
  • Go项目实战

    • 使用Go从零开发一个数据库
    • 🔥使用Go从零开发一个编译器 (opens new window)
    • 🔥使用Go从零开发一个解释器 (opens new window)
    • 🔥用Go从零写一个编排器(类Kubernetes) (opens new window)
  • Rust编程

    • Rust编程指南
  • 数据库

    • SQL零基础指南
    • MySQL开发与调试指南
GitHub (opens new window)
  • C++17 详解 说明
  • 第一部分——语言特性
  • 1. 快速入门
  • 2. 移除或修正的语言特性
    • 2. 移除或修正的语言特性
      • 移除的元素
      • 移除register关键字
      • 额外信息
      • 移除已弃用的operator++(bool)
      • 额外信息
      • 移除已弃用的异常规范
      • 额外信息
      • 移除三字符组
      • 额外信息
      • 修正内容
      • 直接列表初始化的新auto规则
      • 额外信息
      • 不带消息的static_assert
      • 额外信息
      • 基于范围的for循环中begin和end类型不同
      • 额外信息
      • 编译器支持
  • 3. 语言澄清(Language Clarification)
  • 4. 通用语言特性
  • 5. 模板(Templates)
  • 6. 代码标注
  • 第二部分 - 标准库的变化
  • 7. std::optional
  • 8. std::variant
  • 9. std::any
  • 10. std::string_view
  • 11. 字符串转换
  • 12. 搜索器与字符串匹配
  • 13. 文件系统
  • 14. 并行STL算法
  • 15. 标准库中的其他变化
  • 16. 移除和弃用的库特性
  • 第三部分 - 更多示例和用例
  • 17. 使用std::optional和std::variant进行重构
  • 18. 使用[[nodiscard]]强制执行代码契约
  • 19. 用if constexpr替换enable_if——带可变参数的工厂函数
  • 20. 如何实现CSV读取器的并行化
目录

2. 移除或修正的语言特性

# 2. 移除或修正的语言特性

C++17标准有1600多页,相比C++14增加了200多页(例如,2017年7月的草案N4687与C++14草案N4140相比。)!幸运的是,语言规范在一些地方得到了清理,一些旧的或可能有害的特性被清除。本章简要列出了一些被移除或修正的语言元素。有关标准库中的变更列表,请参阅“移除和弃用的库特性”一章。

在本章中,你将了解到:

  • 从语言中移除的内容,如register关键字或针对bool类型的operator++。
  • 得到修正的内容,特别是使用大括号初始化时的auto类型推导。
  • 其他改进,如针对static_assert和基于范围的for循环的改进。

# 移除的元素

C++每次迭代背后的核心概念之一是与以前版本的兼容性。我们希望语言中有新的特性,但同时,我们的旧项目仍应能够编译。然而,有时会有机会移除那些错误的或很少使用的部分。

本节简要介绍从标准中移除的内容。

# 移除register关键字

register关键字在2011年(C++11)已被弃用,从那时起它就不再有实际意义。它在C++17中被移除。该关键字被保留,可能会在未来的标准修订中重新赋予用途(例如,auto关键字就被重新使用,现在是一个全新且强大的特性)。

如果你使用register声明变量:register int a;

你可能会得到以下警告(以下是GCC8.1的警告信息):

warning: ISO C++17 does not allow'register' storage class specifier
1

在Clang(Clang 7.0)中则会报错:

error: ISO C++17 does not allow'register' storage class specifier
1
# 额外信息

该变更在P0001R1 (opens new window)中被提出。

# 移除已弃用的operator++(bool)

针对bool类型的递增运算符operator++已经被弃用很长时间了!委员会早在1998年(C++98)就不建议使用它,但直到现在才最终决定将其从语言中移除。请注意,bool类型从未支持过operator--。

如果你尝试编写以下代码:

bool b; 
b++;
1
2

你应该会从GCC(GCC 8.1)得到类似这样的错误:

error: use of an operand of type 'bool' in 'operator++' is forbidden in C++17
1
# 额外信息

该变更在P0002R1 (opens new window)中被提出。

# 移除已弃用的异常规范

在C++17中,异常规范将成为类型系统的一部分(在下一章“语言澄清”中会讨论)。然而,标准中包含的旧的、已弃用的异常规范既不实用又很少被使用。

例如:

void fooThrowsInt(int a) throw (int ) {
    printf_s("can throw ints\n");
    if (a == 0)
        throw 1; 
}
1
2
3
4
5

特别注意throw(int)这部分。

上述代码自C++11起就已被弃用。唯一实用的异常声明是throw(),表示这段代码不会抛出任何异常。自C++11起,建议使用noexcept。

在Clang 4.0中,你会得到以下错误:

error: ISO C++1z does not allow dynamic exception specifications [-Wdynamic-exception-spec] note: use 'noexcept(false)' instead
1
# 额外信息

该变更在P0003R5 (opens new window)中被提出。

# 移除三字符组

三字符组是一种特殊的字符序列,在系统不支持7位ASCII(如ISO 646)时可以使用。例如,??=会生成#,??-会生成~。(C++的所有基本源字符集都可以用7位ASCII表示)如今,三字符组很少被使用,在翻译阶段移除它们可以使编译过程更简单。以下是直到C++17还在使用的所有三字符组及其替换字符的表格:

三字符组 替换字符
??= #
??( [
??< {
??/ \
??) ]
??> }
??’ ˆ
??! \|
??- ~
# 额外信息

该变更在N4086 (opens new window)中被提出。

# 修正内容

关于什么算是语言标准中的修正,我们可能存在争议。以下有三点内容,看起来像是对之前规则中缺失或存在问题之处的修正。

# 直接列表初始化的新auto规则

自C++11起,就出现了一个奇怪的问题:auto x { 1 };会被推导为std::initializer_list<int>。这种行为并不直观,因为在大多数情况下,人们会期望它的工作方式与int x { 1 };类似。

在现代C++中,花括号初始化是首选模式,但这类异常情况削弱了该特性。

有了新的标准,我们可以修复这个问题,使其推导为int类型。

为实现这一点,我们需要了解两种初始化方式——复制初始化和直接初始化:

// foo()是一个按值返回某种类型的函数
auto x = foo();   // 复制初始化
auto x{foo()};    // 直接初始化,初始化一个initializer_list(直到C++17)
int x = foo();    // 复制初始化
int x{foo()};     // 直接初始化
1
2
3
4
5

对于直接初始化,C++17引入了新规则:

  • 对于只有一个元素的花括号初始化列表,auto推导将从该元素进行推导。
  • 对于包含多个元素的花括号初始化列表,auto推导将是格式错误的。

例如:

auto x1 = { 1, 2 };   // decltype(x1)是std::initializer_list<int>
auto x2 = { 1, 2.0 }; // 错误:无法推导元素类型
auto x3{ 1, 2 };      // 错误:不是单个元素
auto x4 = { 3 };      // decltype(x4)是std::initializer_list<int>
auto x5{ 3 };         // decltype(x5)是int
1
2
3
4
5
# 额外信息

该变更在N3922 (opens new window)和N3681 (opens new window)中被提出。编译器很早就修复了这个问题,GCC 5.0(2015年中)、Clang 3.8(2016年初)和MSVC 2015(2015年中)中就已提供该改进。这比C++17获批要早得多。

# 不带消息的static_assert

该特性为static_assert添加了一个新的重载。它允许在static_assert中仅使用条件,而无需传递消息。

它将与其他断言(如BOOST_STATIC_ASSERT)兼容。有使用boost经验的程序员现在切换到C++17的static_assert将不会有问题。

static_assert (std::is_arithmetic_v<T>, "T必须是算术类型");
static_assert (std::is_arithmetic_v<T>); // 自C++17起无需消息
1
2

在许多情况下,你检查的条件本身就足够明确,无需在消息字符串中提及。

# 额外信息

该变更在N3928 (opens new window)中被提出。

# 基于范围的for循环中begin和end类型不同

C++11添加了基于范围的for循环:

for (for-range-declaration : for-range-initializer)
	statement;
1
2

根据C++14标准,该循环等效于以下代码:

auto && __range = for-range-initializer;
for ( auto __begin = begin-expr, __end = end-expr;
		__begin != __end;
		++__begin ) {
	for-range-declaration = *__begin;
	statement;
}
1
2
3
4
5
6
7

如你所见,begin和end具有相同的类型。这在一定程度上工作得很好,但可扩展性不足。例如,你可能希望迭代到某个哨兵值(sentinel value),而该值的类型与范围起始值的类型不同。

在C++17中,基于范围的for循环被定义为等效于以下代码:

auto && __range = for-range-initializer;
auto __begin = begin-expr;
auto __end = end-expr;
for ( ; __begin != __end; ++__begin ) {
	for-range-declaration = *__begin;
	statement;
}
1
2
3
4
5
6
7

begin和end的类型可能不同,仅要求存在比较运算符。该变更对现有for循环没有影响,但为库提供了更多选择。例如,这个小的变更使得范围技术规范(Range TS)(以及C++20中的范围库)能够与基于范围的for循环协同工作。

# 额外信息

该变更在P0184R0(https://wg21.link/p0184r0)中被提出。

# 编译器支持

特性 GCC Clang MSVC
移除register关键字 7.0 3.8 VS 2017 15.3
移除已弃用的operator++(bool) 7.0 3.8 VS 2017 15.3
移除已弃用的异常规范 7.0 4.0 VS 2017 15.5
移除三字符组 5.1 3.5 VS 2010
直接列表初始化的新auto规则 5.0 3.8 VS 2015
不带消息的static_assert 6.0 2.5 VS 2017
基于范围的for循环中begin和end类型不同 6.0 3.6 VS 2017
上次更新: 2025/04/01, 13:21:34
1. 快速入门
3. 语言澄清(Language Clarification)

← 1. 快速入门 3. 语言澄清(Language Clarification)→

最近更新
01
第二章 关键字static及其不同用法
03-27
02
第一章 auto与类型推导
03-27
03
第四章 Lambda函数
03-27
更多文章>
Copyright © 2024-2025 沪ICP备2023015129号 张小方 版权所有
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式