C++20

C++20，是繼C++17之後的C++編程語言的ISO/IEC標準修訂版的名稱。2020年2月，該標準在布拉格的會議上由WG21進行了技術定稿。同年9月4日草案獲得批准後，C++20同年12月正式發布。相比 C++17，C++20引入了新的語言特性，如概念、模塊、操作符“”、協程、指定初始化、新標準屬性等。C++20庫標準還加入了範圍、特性測試宏和位操作等。

**特性改動**

**新增語言特性**

**功能特性測試**
自C++11之後標準引入了大量的C++語言、庫特性，在20標準前為了區分這些特性是否生效只能判斷C++標準。20標準為這些語言和程序庫的功能特性定義了一組預處理器宏，使之成為檢測這些功能特性是否存在的一種簡單且可移植的方式。測試宏展開會得到該語言、庫特性添加到標準草案中的年份和月份，如果該特性有顯著變更，宏展開的時間也為更新。- 屬性測試宏
__has_cpp_attribute( 屬性記號 )
宏函數，用以檢測屬性是否支持，如：
#if __has_cpp_attribute(nodiscard) > 201603L
#pragma message("nodiscard version is c++20")
#endif- 語言特性測試宏
用以檢測當前某個語言功能特性是否支持，單個宏，如：
#if __cpp_concepts >= 201907L
#pragma message("support concepts")
#endif- 標準庫特性測試宏
用以檢測當前某個標準庫特性是否支持，單個宏，不由編譯器預定義，由頭文件定義：
#ifdef __cpp_lib_bitops
#pragma message("support bitops")
#endif

**三路比較和比較操作符的默認**
新增三路比較運算符，又稱spaceship operator，其形式為：
左操作數  右操作數
表達式返回一個對象，使得- 如果 a  b)  b，那麼 (a  b) > 0- 而如果 a 和 b 相等/等價，那麼 (a  b) == 0。
三路比較操作符會作為 >=四個操作符的重寫候選，若決議選擇了帶參數順序的operator，則對於操作如x @ y，執行 x  y @ 0，對於不帶參數順序的執行 0 @ x  y。
新增可以將比較操作符顯式預置=default來要求編譯器為某個類生成對應比較，比如：
struct Point
{
int x;
int y;
auto operator(const Point&) const = default;
};

**聚合體指派初始化**
聚合體初始化的語法糖，在c++11的聚合體初始化基礎上，增加了可以指派具體值的語法：
struct U {
int a;
float b;
};
U u1{ 1, 2.0 };
U u2{ .a = 1, .b = 2.0 };

**範圍for中的初始化語句和初始化器**
17標準中給if和switch語句加了初始化語句，20標準則給基於範圍的for加了初始化語句：
std::initializer_list il{ 1, 2, 3 };
for (size_t index{ 0 }; auto& i : il) {
std::cout 

**UTF8字符基礎類型char8_t**
新增了基礎類型char8_t用以表示UTF8字符，與11標準中的char16_t、char32_t一樣同為語言關鍵字，char8_t的出現主要是為了和舊有的char區分，專門用於表示utf8字符。相對應的標準庫``增加了std::u8string的別名，以下來自gcc13：
#if __cplusplus >= 201703L && _GLIBCXX_USE_CXX11_ABI
#include 
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace pmr {
template>
using basic_string = std::basic_string>;
using string    = basic_string;
#ifdef _GLIBCXX_USE_CHAR8_T
using u8string  = basic_string;
#endif
using u16string = basic_string;
using u32string = basic_string;
using wstring   = basic_string;
} // namespace pmr
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // C++17

**新屬性**

**= no_unique_address =**
該屬性適用於非位域非靜態數據成員，指示編譯器可以優化當前成員使其與其他非靜態數據成員重疊，減少內存佔用。如果該成員為空類型（不具有數據成員），則編譯器優化為不佔空間；如果該成員不為空，則其尾隨填充空間可被其他數據成員佔用。兩個場景例子：
```cpp
struct Empty {};
struct WithEmpty {
int32_t x;  // 4字節
Empty e;  // 1字節（填充至對齊）
};  // 總大小8（4+1+3填充）
struct WithEmptyAttri {
int32_t x;  // 4字節
no_unique_address Empty e;  // 優化為不佔空間
};  // 總大小4字節
struct NonEmpty {
int32_t x;  // 4 字節
no_unique_address char y;  // 1字節，無法優化，仍需對齊，*注意這裡指定了no_unique_address
// 3 字節填充
};  // 總大小8字節
struct WithNonEmpty {
NonEmpty ne;  // 8 字節，未指定no_unique_address，z不可複用ne空間
char z;  // 1字節, 需對齊
// 3 字節填充
};  // 總大小12字節
struct Optimized {
no_unique_address NonEmpty ne;  // 8 字節
char z;  // 可以複用 ne 的尾隨填充
};
int main() {
static_assert(sizeof(WithEmpty) == 8);
static_assert(sizeof(WithEmptyAttri) == 4);
static_assert(sizeof(NonEmpty) == 8);
static_assert(sizeof(WithNonEmpty) == 12);
static_assert(sizeof(Optimized) == 8);
WithNonEmpty wn;
assert(&wn.z == &wn.ne.y + 4);
Optimized o;
assert(&o.z == &o.ne.y + 1);
return 0;
}

**= likely與unlikely =**
現代cpu有指令預取和分支預測功能，在gcc以往也有__builtin_expect，相對應的20標準新增了likely和unlikely屬性作為c++標準的分支預測優化屬性，用於給程序員協助編譯器完成分支預測。

**註釋**

**另見**
C++
*C++23
*C++17
*C++14
*C++11
category:C++