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 };


範圍for中的初始化語句和初始化器

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;
}

UTF8字符基礎類型char8_t

新增了基礎類型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

新屬性

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++標準的分支預測優化屬性,用於給程序員協助編譯器完成分支預測。


注釋

另見

Loading related searches...

Wikiwand - on

Seamless Wikipedia browsing. On steroids.