C++20
2020版C++編程語言標準 来自维基百科,自由的百科全书
C++20,是繼C++17之後的C++編程語言的ISO/IEC標準修訂版的名稱。[1]2020年2月,該標準在布拉格的會議上由WG21進行了技術定稿[2]。同年9月4日草案獲得批准後,C++20同年12月正式發布。[3]相比 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
- 標準庫特性測試宏
用以檢測當前某個標準庫特性是否支持,單個宏,不由編譯器預定義,由<version>頭文件定義:
#ifdef __cpp_lib_bitops
#pragma message("support bitops")
#endif
新增三路比較運算符,又稱spaceship operator,其形式為:
左操作数 <=> 右操作数
表達式返回一個對象,使得
- 如果 a < b,那麼 (a <=> b) < 0
- 如果 a > 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 };
17標準中給if和switch語句加了初始化語句,20標準則給基於範圍的for加了初始化語句:
std::initializer_list<int> il{ 1, 2, 3 };
for (size_t index{ 0 }; auto& i : il) {
std::cout << std::format("index {} value is {}", index++, i) << std::endl;
}
新增了基礎類型char8_t用以表示UTF8字符,與11標準中的char16_t、char32_t一樣同為語言關鍵字,char8_t的出現主要是為了和舊有的char區分,專門用於表示utf8字符。相對應的標準庫`<string>`增加了std::u8string的別名,以下來自gcc13:
#if __cplusplus >= 201703L && _GLIBCXX_USE_CXX11_ABI
#include <bits/memory_resource.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
namespace pmr {
template<typename _CharT, typename _Traits = char_traits<_CharT>>
using basic_string = std::basic_string<_CharT, _Traits,
polymorphic_allocator<_CharT>>;
using string = basic_string<char>;
#ifdef _GLIBCXX_USE_CHAR8_T
using u8string = basic_string<char8_t>;
#endif
using u16string = basic_string<char16_t>;
using u32string = basic_string<char32_t>;
using wstring = basic_string<wchar_t>;
} // namespace pmr
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // C++17
該屬性適用於非位域非靜態數據成員,指示編譯器可以優化當前成員使其與其他非靜態數據成員重疊,減少內存占用。如果該成員為空類型(不具有數據成員),則編譯器優化為不占空間;如果該成員不為空,則其尾隨填充空間可被其他數據成員占用。兩個場景例子: ```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;
}
現代cpu有指令預取和分支預測功能,在gcc以往也有__builtin_expect,相對應的20標準新增了likely和unlikely屬性作為c++標準的分支預測優化屬性,用於給程序員協助編譯器完成分支預測。
注釋
另見
Wikiwand - on
Seamless Wikipedia browsing. On steroids.