第1章 基础知识
为了使长字面常量更易读,可以使用单引号(’)作为数字分隔符。
int n = 123'456'789;
对于带初始化的
if
语句,如果条件是检验变量是否为 0(或者 nullptr),可以省略条件的显示描述。vector<int> v; // 下面两个if语句意义相同 if (auto n = v.size(); 0 != n) {} if (auto n = v.size()) {}
第2章 用户自定义类型
使用
variant
代替union
。vector<variant<int, string>> vv = { "kibazen.cn", 8888 }; for (const auto& v : vv) { if (holds_alternative<int>(v)) { cout << "int value with: " << get<int>(v) << endl; } else if (holds_alternative<string>(v)) { cout << "string value with: " << get<string>(v) << endl; } }
默认情况下,
enum
只定义了赋值、初始化和比较(如 == 和 <)操作。但是枚举类型是一种用户自定义类型,所以可以为枚举类型定义别的运算符。// enum 和 enum class 都可以 enum class Color { red, green, blue, }; Color& operator++(Color& c) { switch (c) { case Color::red: return c = Color::green; case Color::green: return c = Color::blue; case Color::blue: return c = Color::red; } }
第3章 模块化
一个单独编译的
.cpp
文件(包括它使用#include
包含的.h
文件)称为一个 编译单元(translation unit) 。头文件
include
和模块module
的差异不仅是语言上的。- 一个模块只会编译一遍(而不是像头文件一样在使用它的每个编译单元中都编译一遍)。
- 两个模块可以按任意顺序导入(import)而不会改变它们的含义。
- 如果你讲一些东西导入一个模块中,则模块的使用者不会隐式获得这些东西的访问权(但也不会被它们所困扰):import 无传递性。
声明为
noexcept
的函数抛出异常时,程序会自动调用terminate()
函数来终止整个程序。结构化绑定。
struct Info { int key; string value; }; Info get_info() { return Info { 1, "k" }; } auto [k, v] = get_info(); map<int, string> m = { { 1, "k" } }; for (const auto& [k, v] : m) {}
第4章 类
第5章 基本操作
- 右值引用的含义是,引用一个别人无法赋值的内容,所以我们可以安全地”窃取”它的值。
第6章 模板
C++17中允许从构造函数参数中推断模板参数。
pair p = { 1, 5.2 }; // pair<int, double> tuple t = { 1, 1.0, "a"s }; // tuple<int, double, string> vector vi = { 1, 2, 3 }; // vector<int> vector vc = { "a", "b", "c" }; // vector<const char*> vector vs = { "a"s, "b"s, "c"s }; // vector<string>
template <typename T> class Vector { public: using value_type = T; Vector(initializer_list<T> l) { } template <typename Iter> Vector(Iter begin, Iter end) { } T* begin() const { return nullptr; } T* end() const { return nullptr; } }; template <typename Iter> Vector(Iter, Iter) -> Vector<typename iterator_traits<Iter>::value_type>; Vector v1 { 1, 2, 3, 4, 5 }; // Vector<int> Vector v2(v1.begin(), v1.end()); // Vector<int>
第7章 概念和泛型编程
可变参数模板
void print0() { cout << endl; } template <typename T, typename... Tail> void print0(T head, Tail... tail) { cout << head; print0(tail...); } template <typename T, typename... Tail> void print1(T head, Tail... tail) { cout << head; if constexpr (sizeof...(tail) > 0) { print1(tail...); } else { cout << endl; } } print0(1, "char", "string"s); print1(1, "char", "string"s);
表达式折叠
template <typename ...T> void print2(T&&... args) { (cout << ... << args) << endl; } // (((cout << 1) << "char") << "string"s) << endl; print2(1, "char", "string"s);
template <typename... T> auto sum0(T... v) { return (v + ... + 0); } // 右折叠:(1 + (2 + (3 + 0))) sum0(1, 2, 3); template <typename... T> auto sum1(T... v) { return (0 + ... + v); } // 左折叠:(((0 + 1) + 2) + 3) sum1(1, 2, 3);
第8章 标准库概览
第9章 字符串和正则表达式
第10章 输入输出
第11章 容器
为
vector
的下标运算符增加范围检查功能。template <typename T> class Vec : public std::vector<T> { public: using vector<T>::vector; // 使用 vector 的构造函数(但名字是 Vec) T& operator[](int i) { return vector<T>::at(i); } const T& operator[](int i) const { return vector<T>::at(i); } };
第12章 算法
第13章 实用功能
span
的使用void use(span<int> vi) { for (int v : vi) { cout << v << endl; } } int arr[100]; use(arr); vector vi = {1,2,3}; use({vi.begin(), vi.end()});
如果一个
tuple
中的某个元素的类型在tuple
中是唯一的,可以通过其类型来获取它。tuple<int, string> t = { 1, "k"s }; get<string>(t) = "m";
与
pair
类似,只要tuple
的元素支持赋值操作和比较操作,整个tuple
就能进行赋值和比较。标准库提供了三种类型来表达选择:
variant
用来表达一组指定选择中的一个。optional
用来表达一个指定类型的值或者没有值。any
用来表达一组不限数量的可选类型中的一个。
有状态的内存分配系列工具 pmr(polymorphic memory resources) 。
pmr::synchronized_pool_resource pool; struct Event { pmr::vector<int> data = pmr::vector<int> {512, &pool }; }; pmr::list<shared_ptr<Event>> q { &pool }; void producer() { for (int n = 0; n != INT_MAX; ++n) { q.push_back(allocate_shared<Event, pmr::polymorphic_allocator<Event>>(&pool)); } }
第14章 数值
标准库中数学函数报告错误的方式由头文件
#include <cmath>
中宏math_errhandling
的值决定,其值等于MATH_ERRNO
,或MATH_ERREXCEPT
, 或MATH_ERRNO | MATH_ERREXCEPT
。std::cout << "MATH_ERRNO is " << (math_errhandling & MATH_ERRNO ? "set" : "not set") << '\n' << "MATH_ERREXCEPT is " << (math_errhandling & MATH_ERREXCEPT ? "set" : "not set") << '\n'; std::feclearexcept(FE_ALL_EXCEPT); errno = 0; std::cout << "log(0) = " << std::log(0) << '\n'; if(errno == ERANGE) std::cout << "errno = ERANGE (" << std::strerror(errno) << ")\n"; if(std::fetestexcept(FE_DIVBYZERO)) std::cout << "FE_DIVBYZERO (pole error) reported\n";
https://en.cppreference.com/w/cpp/numeric/math/math_errhandling
第15章 并发
scoped_lock
允许同时获取多个锁。scoped_lock lck { mutex1, mutex2, mutex3 };
shared_mutex
支持读写锁机制。shared_mutex mx; void reader() { shared_lock lck { mx }; } void writer() { unique_lock lck { mx }; }