1. C++14
不同于重量級的 C++11 給 C++ 世界帶來的脫胎換骨煥然一新,C++14 的體量就比較小。
1.1. 語法級
1.1.1. 字面量
是的,二進(jìn)制字面量終于來了,如 101010b。數(shù)字分位符也來了,如 int i = 424'242;。
1.1.2. lambda 形參類型推導(dǎo)
lambda 的形參類型可使用 auto 推導(dǎo),如:
auto l = [](auto i) { return i + 1; };
1.1.3. 函數(shù)返回類型推導(dǎo)
函數(shù)的返回類型可使用 auto 推導(dǎo),如:
auto f(int i) {
return i + 1;
}
如果函數(shù)中有多個(gè) return 語句,則必須可推斷為相同的類型。如果函數(shù)中存在遞歸調(diào)用,則遞歸調(diào)用之前必須有至少一個(gè)可推斷返回類型的 return 語句。
1.1.4. constexpr 函數(shù)
對 constexpr 函數(shù)的限制有所放寬,constexpr 函數(shù)中可包含:
- 任何聲明,除了 static 變量、thread_local 變量、沒有初始化的變量
- 分支和循環(huán)語句
- 表達(dá)式可改變一個(gè)對象的值,只需該對象的生命周期在函數(shù)內(nèi)
1.1.5. 屬性
使用 deprecated 屬性會在編譯期輸出警告,如:
[[deprecated("f is thread-unsafe. Use g instead.")]]
void f();
1.2. 標(biāo)準(zhǔn)庫級
1.2.1. 自定義字面量
1.2.1.1. 字符串
頭文件
<string>
命名空間std::literals::string_literals
s,創(chuàng)建 std::basic_string,如:
auto str = "abc"s; // std::string s;
1.2.1.2. 時(shí)間
頭文件
<chrono>
命名空間std::literals::chrono_literals
h、min、s、ms、us、ns,創(chuàng)建 std::chrono::duration,如:
auto dur = 42s; // std::chrono::seconds dur;
1.2.1.3. 復(fù)數(shù)
頭文件
<complex>
命名空間std::literals::complex_literals
if、i、il,創(chuàng)建 std::complex<float>、std::complex<double>、std::complex<long double>,如:
auto z = 42i; // std::complex<double> z;
1.2.2. 容器
1.2.2.1. 元組
頭文件
<utility>
std::get 函數(shù),當(dāng)元組中只有一個(gè)字段屬于某種類型,則可使用該類型來訪問該字段,如:
std::tuple<int, std::string, std::string> t(42, "abc", "abc");
int i = std::get<int>(t);
1.2.3. 編譯時(shí)元編程
頭文件
<type_traits>
std::is_final 類用于斷言一個(gè)類是否禁止繼承。
1.2.4. 多線程
頭文件
<shared_mutex>
1.2.4.1. shared_timed_mutex
std::shared_timed_mutex 類作為讀寫互斥量,lock_shared、try_lock_shared、try_lock_shared_for、try_lock_shared_until 和 unlock_shared 方法用于讀互斥,而在 std::timed_mutex 中也包含同名的 lock、try_lock、try_lock_for、try_lock_until 和 unlock 方法用于寫互斥。
1.2.4.2. shared_lock
std::shared_lock 類與 std::unique_lock 的方法構(gòu)成完全相同,只是 std::shared_lock 必須基于一個(gè)可共享的互斥量,如 std::shared_timed_mutex。
2. C++17
2.1. 語法級
2.1.1. 結(jié)構(gòu)化綁定
結(jié)構(gòu)化綁定聲明可用于數(shù)組、std:tuple、std::pair,或用戶定義的結(jié)構(gòu),如:
int arr[2] = {42, 42};
auto [i, j] = arr;
auto &[ri, rj] = arr;
2.1.2. 折疊表達(dá)式
折疊表達(dá)式簡化了模板的變長類型參數(shù)的使用,有以下四種折疊:
-
(e op ...),展開為(e1 op (e2 op (... op eN))) -
(... op e),展開為(((e1 op e2) op ...) op eN) -
(e op ... op i),展開為(e1 op (e2 op (... op (eN op i)))) -
(i op ... op e),展開為((((i op e1) op e2) op ...) op eN)
其中,e為包含模板變長類型參數(shù)對應(yīng)的形參包的表達(dá)式,i為不包含變長形參包的表達(dá)式,op為一個(gè)二元操作符,e1、e2至eN為變長形參包的每個(gè)分量對應(yīng)的表達(dá)式,如:
template<typename... Args>
void print(Args... args) {
(std::cout << ... << args) << '\n';
// print(42, 'a', "abc"); =>
// (((std::cout << 42) << 'a') << "abc") << '\n';
}
template<typename T, typename... Args>
void push_back(std::vector<T> &v, Args... args) {
(v.push_back(args), ...);
// push_back(v, 42, 42.0, 'a'); =>
// ((v.push_back(42), v.push_back(42.0)), v.push_back('a'));
}
2.1.3. lamdba 捕獲 *this
lambda 以拷貝構(gòu)造捕獲 this,如:
class Cls {
void f() {
[*this](){}();
[=, *this](){}();
}
};
2.1.4. constexpr if
constexpr if 屬于元編程的范疇,使用一個(gè)常量表達(dá)式作為條件,在編譯時(shí)選擇分支,未被選擇的分支最終不會被編譯,當(dāng)然在運(yùn)行時(shí)也不會有跳轉(zhuǎn),對運(yùn)行時(shí)的性能有所增強(qiáng),如:
template<typename T> void f() {
if constexpr (sizeof(T) == 8) {
} else if constexpr (sizeof(T) == 4) {
} else {
}
}
2.1.5. if/switch 初始化
Golang 中慣常使用的,讓外層命名空間更精簡的語句,如:
if (int i = f(); g(i) > i) {
2.1.6. 類模板類型參數(shù)推導(dǎo)
初始化一個(gè)類模板的對象,模板的類型參數(shù)可自動推導(dǎo),如:
std::tuple t(42, 42.0); // std::tuple<int, double>
2.1.7. 模板非類型參數(shù)類型推導(dǎo)
模板非類型參數(shù)的類型可使用 auto 推導(dǎo),如:
template<auto i> class Cls;
Cls<42> c; // template<int i> class Cls
2.1.8. 嵌套命名空間簡化
對于嵌套的命名空間,之前需要寫成如:
namespace N {
namespace N1 {
}
}
現(xiàn)可簡化為:
namespace N::N1 {
}
2.2. 標(biāo)準(zhǔn)庫級
2.2.1. 容器
2.2.1.1. 字符串
頭文件
<charconv>
std::from_chars 和 std::to_chars 函數(shù)用于字符串轉(zhuǎn)換。
2.2.1.2. 字符串 view
頭文件 `<string_view>
參考文檔
std::basic_string_view 類類似 std::basic_string 的讀寫行為,但不掌管底層內(nèi)存的生命周期。
2.2.1.3. map
頭文件
<map>
std::map 的 try_emplace 方法,僅當(dāng) key 不存在時(shí)才執(zhí)行與 emplace 相同的操作。
std::map 的 insert_or_assign 方法,顧名思義。
std::map 的 extract 方法,更換 map 中分量的 key 而不重新分配空間的唯一方式,如:
std::map<int, std::string> m;
auto node = m.extract(42);
node.key() = 7;
m.insert(std::move(node));
std::map 的 merge 方法,將傳入容器中的分量抽取到 this 中,key 存在的分量則不抽取,如:
std::map<int, std::string> m1 = {{1, "a"}, {2, "b"}};
std::map<int, std::string> m2 = {{2, "d"}, {3, "c"}};
m1.merge(m2);
// m1 == {{1, "a"}, {2, "b"}, {3, "c"}}
// m2 == {{2, "d"}}
2.2.1.4. 元組
頭文件
<tuple>
std::apply 函數(shù),將一個(gè) std::tuple、std::pair 或 std::array 中的分量作為參數(shù)來調(diào)用可調(diào)用對象,如:
std::apply([](auto a, auto b) { return a + b; }, std::tuple(42, 42));
2.2.1.5. optional
頭文件
<optional>
參考文檔
std::optional 類,類似諸多含有 null-safety 特性的語言中的 Option 類,如:
std::optional<std::string> opt("abc");
std::string &rs = opt.value();
std::optional<int> opt1(std::nullopt);
opt1.has_value(); // false
2.2.1.6. any
頭文件
<any>
參考文檔
std::any 類,一種類型安全的泛型單值容器。注意這不是一個(gè)類模板,不同實(shí)際類型的對象之間可以相互賦值、交換,可放入同一個(gè)線性、關(guān)聯(lián)容器,如:
std::any a(42);
int &ri = std::any_cast<int&>(a);
2.2.1.7. variant
頭文件
<variant>
參考文檔
std::variant 類,一種類型安全的聯(lián)合體,不可存放引用、數(shù)組和 void 類型,如:
std::variant<std::string, int> var(42);
int &ri = std::get<int>(var); // 42
int &rj = std::get<1>(var); // 42
var.index(); // 1
2.2.2. 算法
頭文件
<algorithm>
std::clamp 函數(shù)用于夾。
頭文件
<numeric>
std::reduce 函數(shù),是的就是那個(gè) reduce。
std::inclusive_scan 和 std::exclusive_scan 函數(shù)用于前綴運(yùn)算。參考文檔
std::gcd 函數(shù)用于求最大公約數(shù)。std::lcm 函數(shù)用于求最小公倍數(shù)。
2.2.3. 文件系統(tǒng)
頭文件
<filesystem>
參考文檔
文件系統(tǒng) API 終于正式進(jìn)入標(biāo)準(zhǔn)庫。
2.2.4. 動態(tài)內(nèi)存管理
2.2.4.1. new 操作符
new 和 new[] 操作符現(xiàn)在可以傳入第二個(gè)類型為 std::align_val_t 的參數(shù)用于內(nèi)存對齊。
2.2.4.2. 分配器
頭文件
<memory_resource>
std::pmr::polymorphic_allocator 類實(shí)現(xiàn)了一個(gè)可供容器使用的運(yùn)行時(shí)多態(tài)分配器,由一個(gè) std::pmr::memory_resource 類的派生類提供分配策略,包括簡單使用 new 和 delete 操作符的 std::pmr::new_delete_resource 類和池化的 std::pmr::synchronized_pool_resource 類等。
2.2.4.3. 未初始化內(nèi)存算法
頭文件
<memory>
std::uninitialized_move 函數(shù)將對象移動構(gòu)造至未初始化內(nèi)存。std::uninitialized_default_construct 函數(shù)缺省構(gòu)造至未初始化內(nèi)存。std::uninitialized_default_construct 函數(shù)值初始化構(gòu)造至未初始化內(nèi)存。
std::destroy_at 函數(shù)析構(gòu)指針指向的對象。std::destroy 函數(shù)析構(gòu)迭代器指向的對象。
2.2.5. 編譯時(shí)元編程
頭文件
<type_traits>
2.2.5.1. 靜態(tài)斷言
std::is_swappable_with 類用于斷言兩個(gè)類型之間是否可調(diào)用 std::swap。
std::is_invocable 類用于斷言一個(gè)可調(diào)用類型是否可由一個(gè)類型序列作為參數(shù)來調(diào)用。
std::is_aggregate 類用于斷言一個(gè)類型是否聚合類型。
2.2.5.2. 模板元類
std::conjunction 類構(gòu)成類型之間的邏輯與。參考文檔
std::disjunction 類構(gòu)成類型之間的邏輯或。參考文檔
std::negation 類構(gòu)成類型的邏輯非。參考文檔
2.2.6. 多線程
2.2.6.1. shared_mutex
頭文件
<shared_mutex>
參考文檔
shared_mutex 類之于 shared_timed_mutex,如同 mutex 之于 timed_mutex。shared_mutex 之于 mutex,如同 shared_timed_mutex 之于 timed_mutex。
2.2.6.2. scoped_lock
頭文件
<mutex>
參考文檔
scoped_lock 類用于 RAII 式的互斥量包裝,在析構(gòu)時(shí)釋放互斥量。
2.2.7. 數(shù)學(xué)特殊函數(shù)
頭文件
<cmath>
參考文檔
3. C++20
3.1. 語法級
3.1.1. 字符
char8_t 類型為 8 位字符類型,表示一個(gè) UTF-8 的編碼,與 unsigned char 性質(zhì)相同。C++20 起使用前綴 u8 產(chǎn)生的字符串字面量,其字符類型變?yōu)?char8_t。
3.1.2. 三路比較操作符
是的你沒有看錯(cuò),C++20 居然增加了一個(gè)用非字母書寫的二元操作符,一個(gè)看起來挺鬼畜的符號。三路比較操作符返回一個(gè)序類型,參考 3.2.1. 章節(jié)。
3.1.3. 初始化
指派初始化器,每個(gè)指派符必須指定一個(gè)直接非靜態(tài)數(shù)據(jù)成員,初始化表達(dá)式中指定的順序必須與類型定義中的成員順序相同,未指定的字段進(jìn)行值初始化,如:
struct S { int a; int b; int c; };
S s{ .a = 1, .c = 2 };
3.1.4. 范圍 for 初始化
類似 if 初始化,如:
for (auto v = f(); auto e : v) {
3.1.5. 常量表達(dá)式
consteval 關(guān)鍵字聲明函數(shù)立即函數(shù),即每次調(diào)用必須產(chǎn)生常量表達(dá)式,蘊(yùn)含 constexpr 和 inline。
constinit 關(guān)鍵字聲明變量擁有靜態(tài)或線程生命周期。
3.1.6. 概念
我們知道 C++ 的一項(xiàng)原則,要增加任何新內(nèi)容,能在標(biāo)準(zhǔn)庫實(shí)現(xiàn)的就不增加新語法。從 C++98 以來,即使是增加新語法,也無非是在現(xiàn)有語言要素上作出調(diào)整和補(bǔ)充,比如類型的自動推導(dǎo)、模板的變長類型參數(shù)就算其中的重大更新了,而閉包也只是仿函類的語法糖。但這次的概念(concept),則是新增了一項(xiàng)全新的語言要素類型,堪稱 C++20 三巨頭之首。
概念是一個(gè)對模板類型實(shí)參的約束,可對模板類型實(shí)參進(jìn)行編譯時(shí)元編程的斷言。而一個(gè)模板的模板類型形參可聲明受概念的約束,編譯器實(shí)例化模板時(shí),會對模板類型實(shí)參執(zhí)行概念的編譯時(shí)元編程代碼,檢查其是否滿足約束。類似的,我們能在諸如 Rust/Java 中約束泛型參數(shù)必須繼承于某個(gè)類或?qū)崿F(xiàn)了某個(gè)接口,相比之下顯然 C++ 概念的表達(dá)能力更強(qiáng),直逼 Haskell 的 typeclass。
概念的定義,如:
template<typename T, typename U>
concept ConceptA = std::is_xxx<T, U>::value && std::is_yyy<U, T>::value;
template<typename T, typename U>
concept ConceptB = std::is_zzz<T, U>::value || !ConceptA<U, T>;
template<typename T, typename U>
concept ConceptC = requires(T t, U u) {
t + u;
typename T::U;
};
顯然,可以將概念看作一個(gè)常量布爾表達(dá)式或一個(gè)函數(shù)。概念不能遞歸定義,不能顯式實(shí)例化、特化,不能約束另一個(gè)概念。以 requires 開頭的表達(dá)式類似一個(gè)函數(shù),其 requires 體中的語句分為以下類型,可混合出現(xiàn):
- 簡單 requires:僅一個(gè)表達(dá)式。不進(jìn)行求值,只檢查語法合法,如:
template<typename T, typename U>
concept Concept = requires(T t, U u) {
t + u;
};
- 類型 requires:
typename跟一個(gè)類型名。檢查類型名合法,如:
template<typename T>
concept Concept = requires(T t) {
typename T::U;
};
- 復(fù)合 requires:一個(gè)花括號包含的表達(dá)式,跟一個(gè)箭頭,再跟一個(gè)編譯時(shí)元編程斷言類。檢查花括號中的表達(dá)式對應(yīng)的
decltype(())滿足斷言,如:
template<typename T>
concept Concept = requires(T t) {
{t + 1} -> std::same_as<T>; // to check std::same_as<decltype((t + 1)), T>::value
};
- 嵌套 requires:
requires跟一個(gè)約束。引用其他約束,如:
template<typename T>
concept Concept = requires(T t) {
requires ConceptA<T*>;
};
模板指定概念時(shí),可在模板參數(shù)列表中用概念替代 typename,或在模板參數(shù)列表之后使用 requires 子句,或者聲明的主體之后使用 requires 子句,或在以上三處中的多處同時(shí)出現(xiàn)而構(gòu)成邏輯與的關(guān)系,如:
template<ConceptA T, ConceptB<int> U> requires ConceptC<T, U>
void f(T, U) requires ConceptD<T>;
// T is constrainted by ConceptA<T> and ConceptC<T, U> and ConceptD<T>
// U is constrainted by ConceptB<U, int> and ConceptC<T, U>
requires 子句中也可使用邏輯與、或、非,如:
template<typename T> requires (ConceptA<T> && ConceptB<T>)
void f(T);
例如,一個(gè)函數(shù)接受一個(gè)對象及其 run 方法的參數(shù),run 方法有特定的參數(shù)列表,如果對象存在此 run 方法,則傳參調(diào)用該方法并返回 true,否則不調(diào)用并返回 false。顯然,在動態(tài)語言中這個(gè)函數(shù)很容易實(shí)現(xiàn),但在 C++ 這樣的靜態(tài)語言中則需要使用到編譯時(shí)的模板元編程技巧。在 C++11 中,我們可以用兩層的 sfinae 來實(shí)現(xiàn):
#include <type_traits>
template<typename T, typename ...Args> struct has_method_run {
private:
template<typename U> static auto f(int) ->
decltype(std::declval<U>().run(std::declval<Args>()...), std::true_type());
template<typename U> static std::false_type f(char);
public:
enum { value = decltype(f<T>(0))::value };
};
template<typename T, typename ...Args> auto run(T &&t, Args &&...args) ->
typename std::enable_if<has_method_run<T, Args...>::value, bool>::type {
t.run(std::forward<Args>(args)...);
return true;
}
template<typename T, typename ...Args> auto run(T &&t, Args &&...args) ->
typename std::enable_if<!has_method_run<T, Args...>::value, bool>::type {
return false;
}
看起來有些天書。在 C++17 中,可以更優(yōu)雅一點(diǎn),我們可以使用 if constexpr 來消除 run 函數(shù)必需的重載,從而讓 sfinae 減少到只有一層:
#include <type_traits>
template<typename T, typename ...Args> struct has_method_run {
private:
template<typename U> static auto f(int) ->
decltype(std::declval<U>().run(std::declval<Args>()...), std::true_type());
template<typename U> static std::false_type f(char);
public:
enum { value = decltype(f<T>(0))::value };
};
template<typename T, typename ...Args> bool run(T &&t, Args &&...args) {
if constexpr (has_method_run<T, Args...>::value) {
t.run(std::forward<Args>(args)...);
return true;
}
return false;
}
而在 C++20 中,我們可以使用 concept 讓 sfinae 變得更優(yōu)雅:
#include <type_traits>
template<typename T, typename ...Args> concept must_have_method_run = requires(T t, Args ...args) {
t.run(args...);
};
template<typename T, typename ...Args> struct has_method_run {
private:
template<typename U> requires must_have_method_run<U, Args...> static std::true_type f(int);
template<typename U> static std::false_type f(char);
public:
enum { value = decltype(f<T>(0))::value };
};
template<typename T, typename ...Args> bool run(T &&t, Args &&...args) {
if constexpr (has_method_run<T, Args...>::value) {
t.run(std::forward<Args>(args)...);
return true;
}
return false;
}
3.1.7. 協(xié)程
[參考文檔](https://en.cppreference.com/w/cpp/language/coroutines)
C++20 三巨頭之二。專門一篇
3.1.8. 模塊
C++20 三巨頭之三。模塊與命名空間之間還是正交的,日你先人,略。
3.2. 標(biāo)準(zhǔn)庫級
3.2.1. 比較與排序
頭文件
<compare>
是的,在 Rust 當(dāng)中會見到的那些抽象代數(shù)的概念,現(xiàn)在來到了 C++ 的標(biāo)準(zhǔn)庫中。
std::partial_ordering 類實(shí)現(xiàn)了偏序概念。其中包含以下同類 constexpr 靜態(tài)成員常量:less、equivalent、greater、unordered,分別表示小于、等價(jià)、大于、不可比較。不可隱式轉(zhuǎn)換為 std::weak_ordering 和 std::strong_ordering。對于三路比較返回 std::partial_ordering 的類型,其 <、==、> 操作符可均返回 false。
std::weak_ordering 類實(shí)現(xiàn)了弱序概念。其中包含以下同類 constexpr 靜態(tài)成員常量:less、equivalent、greater,分別表示小于、等價(jià)、大于。可隱式轉(zhuǎn)換為 std::partial_ordering,不可隱式轉(zhuǎn)換為 std::strong_ordering。對于三路比較返回 std::weak_ordering 的類型,其 <、==、> 操作符需有且僅有一個(gè)返回 true。
std::strong_ordering 類實(shí)現(xiàn)了強(qiáng)序概念。其中包含以下同類 constexpr 靜態(tài)成員常量:less、equivalent、equal、greater,分別表示小于、等價(jià)、等價(jià)、大于。可隱式轉(zhuǎn)換為 std::partial_ordering 和 std::weak_ordering。對于三路比較返回 std::strong_ordering 的類型,其 <、==、> 操作符需有且僅有一個(gè)返回 true。
例如,兩個(gè) int 類型的變量之間的三路比較操作符返回一個(gè) std::strong_ordering 類型,而兩個(gè) double 類型則返回 std::partial_ordering 類型,因?yàn)楦↑c(diǎn)數(shù)存在不可比較的 NaN 值。以上三個(gè)序類均重載了 ==、<、>、<=、>=、<=> 操作符,可與同類型對象或 0 字面量進(jìn)行比較。
std::common_comparison_category 類斷言多個(gè)類之間能轉(zhuǎn)換為的最強(qiáng)序類。
std::compare_three_way_result 類斷言一個(gè)或兩個(gè)類之間的三路比較操作符的返回類型。
3.2.2. 概念
頭文件
<concepts>
參考文檔
3.2.3. 工具庫
3.2.3.1. 源碼信息
頭文件
<source_location>
參考文檔
std::source_location 類用于表示源碼信息,作為 __FILE__ 等宏的替代方案,如:
auto sl = std::source_location::current();
sl.line();
3.2.3.2. 格式化
頭文件
<format>
參考文檔
格式化庫作為 printf 函數(shù)族的替代方案,如:
std::string s = std::format("{} {}", "Hello", "world");
3.2.3.3. 時(shí)間
頭文件
<chrono>
參考文檔
時(shí)間庫中增加了日歷和時(shí)區(qū)。
3.2.3.4. 函數(shù)綁定
頭文件
<functional>
std::bind_front 函數(shù)將多個(gè)參數(shù)綁定到可調(diào)用對象的首部形參。
3.2.4. 容器
3.2.4.1. 字符串
頭文件
<string>
std::string 終于有 starts_with 和 ends_with 方法了。
頭文件
<cuchar>
std::c8rtomb 和 std::mbrtoc8 函數(shù)用于單個(gè)編點(diǎn)的 UTF-8 與窄多字節(jié)字符表示之間的轉(zhuǎn)換。
3.2.4.2. span
頭文件
<span>
參考文檔
std::span 類模板用于抽象描述一個(gè)線性序列,可擁有靜態(tài)或動態(tài)的長度。
3.2.4.3. range
頭文件
<ranges>
參考文檔
眾所周知三巨頭一定有四位,range 庫正是 C++20 三巨頭之四。
3.2.5. 算法
頭文件
<numeric>
std::midpoint 函數(shù)用于計(jì)算中點(diǎn)。
頭文件
<bit>
參考文檔
提供二進(jìn)制算法,如 std::popcount 函數(shù)作為 __builtin_popcount 的替代方案,std::countl_zero 函數(shù)作為 __builtin_clz 的替代方案。
3.2.6. 動態(tài)內(nèi)存管理
頭文件
<memory>
std::make_obj_using_allocator 函數(shù)用于創(chuàng)建對象!
std::make_shared 函數(shù)添加了大量重載。參考文檔
3.2.7. 編譯時(shí)元編程
頭文件
<type_traits>
std::remove_cvref 類用于生成去掉引用類型和 cv 限定符的類型。
std::is_bounded_array 類用于斷言一個(gè)類型是否是有已知固定長度的數(shù)組。
3.2.8. 多線程
3.2.8.1. osyncstream
頭文件
<syncstream>
參考文檔
std::osyncstream 作為線程安全的 std::ostream。
3.2.8.2. latch
頭文件
<latch>
參考文檔
std::latch 類作為單次線程屏障。其計(jì)數(shù)不能增加或重置,因此只能使用一次。count_down 方法減計(jì)數(shù),arrive_and_wait 方法減計(jì)數(shù)且阻塞線程直至計(jì)數(shù)為零,wait 方法阻塞線程直至計(jì)數(shù)為零。
3.2.8.3. barrier
頭文件
<barrier>
參考文檔
std::barrier 類作為可復(fù)用線程屏障。不同于 latch,其計(jì)數(shù)為零時(shí)重置,因此可使用多次;不同于 latch,每個(gè)計(jì)數(shù)周期內(nèi),一個(gè)線程只能減計(jì)數(shù)一次。可指定一個(gè)初始計(jì)數(shù)和周期回調(diào),計(jì)數(shù)為零時(shí)調(diào)用周期回調(diào),周期回調(diào)返回之后,所有阻塞線程的方法才返回,并恢復(fù)初始計(jì)數(shù)。arrive 方法減計(jì)數(shù),arrive_and_drop 方法減計(jì)數(shù)且減初始計(jì)數(shù),arrive_and_wait 方法減計(jì)數(shù)且阻塞線程直至計(jì)數(shù)為零,wait 方法阻塞線程直至計(jì)數(shù)為零。
3.2.8.4. semaphore
頭文件
<semaphore>
參考文檔
std::counting_semaphore 類作為信號量。acquire 方法在計(jì)數(shù)大于 0 時(shí)減計(jì)數(shù),否則阻塞線程直至成功減計(jì)數(shù),release 方法加計(jì)數(shù),同時(shí)包含 try_acquire 方法族。
3.2.9. 數(shù)學(xué)常數(shù)
頭文件
<numbers>
參考文檔
A. 附錄
A.1. 關(guān)鍵字
A.1.1. C++11 中新增的關(guān)鍵字
alignas alignof char16_t char32_t constexpr decltype final noexcept nullptr override static_assert thread_local
A.1.2. C++11 中含義有變的關(guān)鍵字
auto class default delete export extern inline mutable sizeof struct using
A.1.3. C++17 中含義有變的關(guān)鍵字
register
A.1.4. C++20 中新增的關(guān)鍵字
char8_t concept consteval constinit co_await co_return co_yield module requires
A.1.5. C++20 中含義有變的關(guān)鍵字
export