diff --git a/README.md b/README.md index 92719d65..5b282674 100644 --- a/README.md +++ b/README.md @@ -14,105 +14,12 @@ ## 目标读者 -1. 本教程假定读者已经熟悉了传统 C++ ,至少在阅读传统 C++ 代码上不具备任何困难。换句话说,那些长期使用传统 C++进行编码的人、渴望在短时间内迅速了解**现代 C++** 特性的人非常适合阅读本书; +1. 本教程假定读者已经熟悉了传统 C++ ,至少在阅读传统 C++ 代码上不具备任何困难。换句话说,那些已经学习过或者长期使用传统 C++进行编码的人、渴望在短时间内迅速了解**现代 C++** 特性的人非常适合阅读本书; 2. 本教程一定程度上介绍了一些现代 C++ 的**黑魔法**,但这些魔法毕竟有限,不适合希望进阶学习现代 C++ 的读者,本教程的定位系**现代 C++ 的快速上手**。当然,希望进阶学习的读者可以使用本书来回顾并检验自己对 **现代 C++** 的熟悉度。 ## 目录 -> 正在向全面介绍 C++17 特性的内容过度 - -- **第一章 C++11/14 简介** - + 概述 - + 被弃用的特性 - + 与 C 的兼容性 -- **第二章 语言可用性的强化** - + `nullptr` 与 `constexpr` - + 类型推导 - + `auto` - + `decltype` - + 尾返回类型、`auto` 与 `decltype` 配合 - - - - + 区间迭代 - + 基于范围的 for 循环 - + 初始化列表 - + `std::initializer_list` - + 统一初始化语法 - + 模板增强 - + 外部模板 - + 尖括号 `>` - + 类型别名模板 - + 变长参数模板 - + 面向对象增强 - + 委托构造 - + 继承构造 - + 显式虚函数重载 - + `override` - + `final` - + 显式禁用默认函数 - + 强类型枚举 -- **第三章 语言运行期的强化** - + lambda 表达式 - + lambda 表达式基础 - + 值捕获 - + 引用捕获 - + 隐式捕获 - + 表达式捕获 - + 泛型 lambda - + 函数对象包装器 - + std::function - + std::bind/std::placeholder - + 右值引用 - + 左值、右值的纯右值、将亡值、右值 - + 右值引用和左值引用 - + 移动语义 - + 完美转发 -- **第四章 对标准库的扩充: 新增容器** - + `std::array` - + `std::forward_list` - + `std::unordered_set` - + `std::unordered_map` - + `std::tuple` - + 基本操作 - + 运行期索引 - + 合并与迭代 -- **第五章 对标准库的扩充: 智能指针和引用计数** - + RAII 与引用计数 - + `std::shared_ptr` - + `std::unique_ptr` - + `std::weak_ptr` -- **第六章 对标准库的扩充: 正则表达式库** - + 正则表达式简介 - + 普通字符 - + 特殊字符 - + 限定符 - + `std::regex` 及其相关 - + `std::regex` - + `std::regex_match` - + `std::match_results` -- **第七章 对标准库的扩充: 语言级线程支持** - + `std::thread` - + `std::mutex` - + `std::unique_lock` - + `std::future` - + `std::packaged_task` - + `std::condition_variable` -- **第八章 其他杂项** - + 新类型 - + `long long int` - + `noexcept` 的修饰和操作 - + 字面量 - + 原始字符串字面量 - + 自定义字面量 -- **第九章 扩展主题: C++17 简介** - + 主要入选特性 - + 非类型模板参数的 `auto` - + `std::variant<>` - + 结构化绑定(Structured bindings) - + 变量声明的强化 - + 未入选特性 - + Concepts +从[这里](book/toc.md)开始阅读。 ## 交流 diff --git a/book/0-preface.md b/book/0-preface.md index fe0a526c..c2592e02 100644 --- a/book/0-preface.md +++ b/book/0-preface.md @@ -1,7 +1,5 @@ # 高速上手现代 C++ 11/14/17 -> 内容修订中 - ## 引言 C++ 是一个用户群体相当大的语言。从 C++98 的出现到 C++11 的正式定稿经历了长达十年多之久的积累。C++14/17 则是作为对 C++11 的重要补充和优化,所有这些新标准中扩充的特性,给 C++ 这门语言注入了新的活力。 @@ -28,102 +26,7 @@ C++17 则是近三年依赖 C++ 社区一致推进的方向,也指出了**现 此外,本教程希望读者在阅读本书后,能够努力在新项目中直接使用 C++17,并努力将旧项目逐步迁移到 C++17。也算是笔者为推进现代 C++ 的普及贡献了一些绵薄之力。 -## 目录 - -> 目录正在向支持 C++17 的内容过度 - -- **第一章 C++11/14/17 简介** - + 概述 - + 被弃用的特性 - + 与 C 的兼容性 -- **第二章 语言可用性的强化** - + `nullptr` 与 `constexpr` - + 类型推导 - + `auto` - + `decltype` - + 尾返回类型、`auto` 与 `decltype` 配合 - - - - + 区间迭代 - + 基于范围的 for 循环 - + 初始化列表 - + `std::initializer_list` - + 统一初始化语法 - + 模板增强 - + 外部模板 - + 尖括号 `>` - + 类型别名模板 - + 变长参数模板 - + 面向对象增强 - + 委托构造 - + 继承构造 - + 显式虚函数重载 - + `override` - + `final` - + 显式禁用默认函数 - + 强类型枚举 -- **第三章 语言运行期的强化** - + lambda 表达式 - + lambda 表达式基础 - + 值捕获 - + 引用捕获 - + 隐式捕获 - + 表达式捕获 - + 泛型 lambda - + 函数对象包装器 - + std::function - + std::bind/std::placeholder - + 右值引用 - + 左值、右值的纯右值、将亡值、右值 - + 右值引用和左值引用 - + 移动语义 - + 完美转发 -- **第四章 对标准库的扩充: 新增容器** - + `std::array` - + `std::forward_list` - + `std::unordered_set` - + `std::unordered_map` - + `std::tuple` - + 基本操作 - + 运行期索引 - + 合并与迭代 -- **第五章 对标准库的扩充: 智能指针和引用计数** - + RAII 与引用计数 - + `std::shared_ptr` - + `std::unique_ptr` - + `std::weak_ptr` -- **第六章 对标准库的扩充: 正则表达式库** - + 正则表达式简介 - + 普通字符 - + 特殊字符 - + 限定符 - + `std::regex` 及其相关 - + `std::regex` - + `std::regex_match` - + `std::match_results` -- **第七章 对标准库的扩充: 语言级线程支持** - + `std::thread` - + `std::mutex` - + `std::unique_lock` - + `std::future` - + `std::packaged_task` - + `std::condition_variable` -- **第八章 其他杂项** - + 新类型 - + `long long int` - + `noexcept` 的修饰和操作 - + 字面量 - + 原始字符串字面量 - + 自定义字面量 -- **第九章 扩展主题: C++17 简介** - + 主要入选特性 - + 非类型模板参数的 `auto` - + `std::variant<>` - + 结构化绑定(Structured bindings) - + 变量声明的强化 - + 未入选特性 - + Concepts +[返回目录](./toc.md) | 上一章 | [下一章](./1-intro.md) ## 许可 diff --git a/book/1-intro.md b/book/1-intro.md index e9f363e7..291fce3b 100644 --- a/book/1-intro.md +++ b/book/1-intro.md @@ -1,40 +1,45 @@ -# 第一章 C++11/14/17 简介 +# 第 1 章 迈向 C++11/14/17 -## 一、被弃用的特性 +[TOC] -在学习 C++1x 之前,我们先了解一下从 C++11 开始,被弃用的主要特性: +## 1.1 被弃用的特性 -> **注意**:弃用不等于废弃,只是用于暗示程序员这些特性将从未来的标准中消失,应该尽量避免使用。但是,已弃用的特性依然是标准库的一部分,并且出于兼容性的考虑,这些特性其实会『永久』保留。 +在学习 C++1x 之前,我们先了解一下从 C++11 开始,被弃用的主要特性: -- **如果一个类有析构函数,为其生成拷贝构造函数和拷贝赋值运算符的特性被弃用了。** +> **注意**:弃用并非彻底不能用,只是用于暗示程序员这些特性将从未来的标准中消失,应该尽量避免使用。但是,已弃用的特性依然是标准库的一部分,并且出于兼容性的考虑,大部分特性其实会『永久』保留。 - **不再允许字符串字面值常量赋值给一个 `char *`。如果需要用字符串字面值常量赋值和初始化一个 `char *`,应该使用 `const char *` 或者 `auto`。** - -```cpp -char *str = "hello world!"; // 将出现弃用警告 -``` + ```cpp + char *str = "hello world!"; // 将出现弃用警告 + ``` - **C++98 异常说明、 `unexcepted_handler`、`set_unexpected()` 等相关特性被弃用,应该使用 `noexcept`。** - **`auto_ptr` 被弃用,应使用 `unique_ptr`。** -- **`register` 关键字被弃用。** +- **`register` 关键字被弃用,可以使用但不再具备任何实际含义。** - **`bool` 类型的 `++` 操作被弃用。** -- **C 语言风格的类型转换被弃用,应该使用 `static_cast`、`reinterpret_cast`、`const_cast` 来进行类型转换。** +- **如果一个类有析构函数,为其生成拷贝构造函数和拷贝赋值运算符的特性被弃用了。** + +- **C 语言风格的类型转换被弃用(即在变量前使用 `(convert_type)`),应该使用 `static_cast`、`reinterpret_cast`、`const_cast` 来进行类型转换。** + +- **特别地,在最新的 C++17 标准中弃用了一些可以使用的 C 标准库,例如 ``、``、`` 与 `` 等** + +- ……等等 还有一些其他诸如参数绑定(C++11 提供了 `std::bind` 和 `std::function`)、`export` 等特性也均被弃用。前面提到的这些特性**如果你从未使用或者听说过,也请不要尝试去了解他们,应该向新标准靠拢**,直接学习新特性。毕竟,技术是向前发展的。 -## 二、与 C 的兼容性 +## 1.2 与 C 的兼容性 -出于一些不可抗力、历史原因,我们不得不在 C++ 中使用一些 C 语言代码(甚至古老的 C 语言代码),例如 Linux 系统调用。在 C++11 出现之前,大部分人当谈及 『C 与 C++ 的区别是什么』时,普遍除了回答面向对象的类特性、泛型编程的模板特性外,就没有其他的看法了,甚至直接回答『差不多』,也是大有人在。下面的韦恩图大致上回答了 C 和 C++ 相关的兼容情况: +出于一些不可抗力、历史原因,我们不得不在 C++ 中使用一些 C 语言代码(甚至古老的 C 语言代码),例如 Linux 系统调用。在 C++1x 出现之前,大部分人当谈及『C 与 C++ 的区别是什么』时,普遍除了回答面向对象的类特性、泛型编程的模板特性外,就没有其他的看法了,甚至直接回答『差不多』,也是大有人在。图 1.2 中的韦恩图大致上回答了 C 和 C++ 相关的兼容情况。 -![](../assets/comparison.png) +![图 1.2: C 和 C++ 互相兼容情况](../assets/comparison.png) -从现在开始,你的脑子里应该树立 **『C++ 不是 C 的一个超集』**这个观念(而且从一开始就不是,后面的进一步阅读的参考文献中给出了 C++98 和 C99 之间的区别)。在编写 C++ 时,也应该尽可能的避免使用诸如 `void*` 之类的程序风格。而在不得不使用 C 时,应该注意使用 `extern "C"` 这种特性,将 C 语言的代码与 C++代码进行分离编译,再统一链接这种做法,例如: +从现在开始,你的脑子里应该树立**『C++ 不是 C 的一个超集』**这个观念(而且从一开始就不是,后面的[进一步阅读的参考文献](#进一步阅读的参考文献)中给出了 C++98 和 C99 之间的区别)。在编写 C++ 时,也应该尽可能的避免使用诸如 `void*` 之类的程序风格。而在不得不使用 C 时,应该注意使用 `extern "C"` 这种特性,将 C 语言的代码与 C++代码进行分离编译,再统一链接这种做法,例如: -```c +```cpp // foo.h #ifdef __cplusplus extern "C" { @@ -48,32 +53,76 @@ int add(int x, int y); // foo.c int add(int x, int y) { -reutrn x+y; + reutrn x+y; } -// main.cpp +// 1.1.cpp #include "foo.h" +#include +#include + int main() { -add(1, 2); -return 0; + [out = std::ref(std::cout << "Result from C code: " << add(1, 2))](){ + out.get() << ".\n"; + }(); + return 0; } ``` + 应先使用 `gcc` 编译 C 语言的代码: ```bash gcc -c foo.c ``` + 编译出 foo.o 文件,再使用 `g++` 将 C++代码和 `.o` 文件链接起来(或者都编译为 `.o` 再统一链接): ```bash -g++ main.cpp foo.o -o main +g++ 1.1.cpp foo.o -std=c++1z -o 1.1 ``` -## 进一步阅读的参考资料 +当然,你可以可以使用 `Makefile` 来编译上面的代码: + +```makefile +C = gcc +CXX = g++ + +SOURCE_C = foo.c +OBJECTS_C = foo.o + +SOURCE_CXX = 1.1.cpp + +TARGET = 1.1 +LDFLAGS_COMMON = -std=c++1z + +all: + $(C) -c $(SOURCE_C) + $(CXX) $(SOURCE_CXX) $(OBJECTS_C) $(LDFLAGS_COMMON) -o $(TARGET) +clean: + rm -rf *.o $(TARGET) +``` + +> 注意,Makefile 中的缩进是制表符而不是空格符,如果你直接复制这段代码到你的编辑器中,制表符可能会被自动替换掉,请自行确保在 Makefile 中的缩进是由制表符完成的。 +> +> 如果你还不知道 Makefile 的使用也没有关系,本教程中不会构建过于复杂的代码,简单的在命令行中使用 `g++ -std=c++1z` 也可以阅读本书。 + +如果你是首次接触现代 C++,那么你很可能还看不懂上面的那一小段代码,即: + +```cpp +[out = std::ref(std::cout << "Result from C code: " << add(1, 2))](){ + out.get() << ".\n"; +}(); +``` + +不必担心,本书的后续章节将为你介绍这一切。 + +[返回目录](./toc.md) | [上一章](./0-preface.md) | [下一章](./2-usability.md) + +## 进一步阅读的参考文献 -1. C++ 语言导学. Bjarne Stroustrup +1. [C++ 语言导学. Bjarne Stroustrup](https://www.amazon.cn/dp/B00WUBYBYS/ref=sr_1_1?ie=UTF8&qid=1522400738&sr=8-1&keywords=C%2B%2B+%E8%AF%AD%E8%A8%80%E5%AF%BC%E5%AD%A6) 2. [C++ 历史](http://en.cppreference.com/w/cpp/language/history) -3. [C++ 1x 特性在 GCC/Clang等编译器中的支持情况](http://en.cppreference.com/w/cpp/compiler_support) +3. [C++ 1x 特性在 GCC/Clang 等编译器中的支持情况](http://en.cppreference.com/w/cpp/compiler_support) 4. [C++98 与 C99 之间的区别](http://david.tribble.com/text/cdiffs.htm#C99-vs-CPP98) ## 许可 diff --git a/book/toc.md b/book/toc.md new file mode 100644 index 00000000..d231fcc0 --- /dev/null +++ b/book/toc.md @@ -0,0 +1,99 @@ +# 高速上手现代 C++ 11/14/17 + +> 正在向全面介绍 C++17 特性的内容过度 + +## 目录 + +- [序言](./0-preface.md) +- [**第 1 章 迈向 C++11/14/17**](./1-intro.md) + + 1.1 被弃用的特性 + + 1.2 与 C 的兼容性 + + 进一步阅读的参考文献 +- **第二章 语言可用性的强化** + + `nullptr` 与 `constexpr` + + 类型推导 + + `auto` + + `decltype` + + 尾返回类型、`auto` 与 `decltype` 配合 + + + + + 区间迭代 + + 基于范围的 for 循环 + + 初始化列表 + + `std::initializer_list` + + 统一初始化语法 + + 模板增强 + + 外部模板 + + 尖括号 `>` + + 类型别名模板 + + 变长参数模板 + + 面向对象增强 + + 委托构造 + + 继承构造 + + 显式虚函数重载 + + `override` + + `final` + + 显式禁用默认函数 + + 强类型枚举 +- **第三章 语言运行期的强化** + + lambda 表达式 + + lambda 表达式基础 + + 值捕获 + + 引用捕获 + + 隐式捕获 + + 表达式捕获 + + 泛型 lambda + + 函数对象包装器 + + std::function + + std::bind/std::placeholder + + 右值引用 + + 左值、右值的纯右值、将亡值、右值 + + 右值引用和左值引用 + + 移动语义 + + 完美转发 +- **第四章 对标准库的扩充: 新增容器** + + `std::array` + + `std::forward_list` + + `std::unordered_set` + + `std::unordered_map` + + `std::tuple` + + 基本操作 + + 运行期索引 + + 合并与迭代 +- **第五章 对标准库的扩充: 智能指针和引用计数** + + RAII 与引用计数 + + `std::shared_ptr` + + `std::unique_ptr` + + `std::weak_ptr` +- **第六章 对标准库的扩充: 正则表达式库** + + 正则表达式简介 + + 普通字符 + + 特殊字符 + + 限定符 + + `std::regex` 及其相关 + + `std::regex` + + `std::regex_match` + + `std::match_results` +- **第七章 对标准库的扩充: 语言级线程支持** + + `std::thread` + + `std::mutex` + + `std::unique_lock` + + `std::future` + + `std::packaged_task` + + `std::condition_variable` +- **第八章 其他杂项** + + 新类型 + + `long long int` + + `noexcept` 的修饰和操作 + + 字面量 + + 原始字符串字面量 + + 自定义字面量 +- **第九章 扩展主题: C++17 简介** + + 主要入选特性 + + 非类型模板参数的 `auto` + + `std::variant<>` + + 结构化绑定(Structured bindings) + + 变量声明的强化 + + 未入选特性 + + Concepts \ No newline at end of file diff --git a/code/1/1.1 b/code/1/1.1 new file mode 100755 index 00000000..01ef1334 Binary files /dev/null and b/code/1/1.1 differ diff --git a/code/1/1.1.cpp b/code/1/1.1.cpp index b5479f37..e4956d76 100644 --- a/code/1/1.1.cpp +++ b/code/1/1.1.cpp @@ -1,13 +1,19 @@ // // 1.1.cpp +// +// chapter 1 introduction // c++1x tutorial // // created by changkun at changkun.de // #include "foo.h" +#include +#include int main() { - add(1, 2); + [out = std::ref(std::cout << "Result from C code: " << add(1, 2))](){ + out.get() << ".\n"; + }(); return 0; } diff --git a/code/1/Makefile b/code/1/Makefile index 96c5f972..267c7151 100644 --- a/code/1/Makefile +++ b/code/1/Makefile @@ -1,6 +1,25 @@ +# +# 1.1.cpp +# +# chapter 1 introduction +# c++1x tutorial +# +# created by changkun at changkun.de +# + +C = gcc +CXX = g++ + +SOURCE_C = foo.c +OBJECTS_C = foo.o + +SOURCE_CXX = 1.1.cpp + TARGET = 1.1 +LDFLAGS_COMMON = -std=c++1z + all: - gcc -c foo.c - g++ 1.1.cpp foo.o -o $(TARGET) + $(C) -c $(SOURCE_C) + $(CXX) $(SOURCE_CXX) $(OBJECTS_C) $(LDFLAGS_COMMON) -o $(TARGET) clean: rm -rf *.o $(TARGET) diff --git a/code/1/foo.c b/code/1/foo.c index a21621e2..f1fab429 100644 --- a/code/1/foo.c +++ b/code/1/foo.c @@ -1,11 +1,12 @@ // // foo.c +// +// chapter 1 introduction // c++1x tutorial // // created by changkun at changkun.de // - #include "foo.h" int add(int x, int y) { diff --git a/code/1/foo.h b/code/1/foo.h index b5d62c60..084fade9 100644 --- a/code/1/foo.h +++ b/code/1/foo.h @@ -1,11 +1,12 @@ // // foo.h +// +// chapter 1 introduction // c++1x tutorial // // created by changkun at changkun.de // - #ifdef __cplusplus extern "C" { #endif