摘要訊息 : 一些 C++ 20 引入的小特性.

0. 前言

C++ 20 引入的絕大多數重要特性我們基本都介紹完了, 可以在 Jonny'Blog 中搜尋 C++ 20 閱覽這些文章. 還有一些小特性也是 C++ 20 引入的, 本文文章將通過羅列的方式介紹一部分特性.

1. 名稱查找例外擴展到樣板

《C++ 學習筆記》Code 101 附近, 我們提到了名稱查找中的一個例外情況, 就是當函式參數存在類別的時候, 編碼器還會去這個類別所在的可視範圍之內進行函式匹配. 這個規則本來是不可以用在函式樣板上的, 但是 C++ 20 提案 P0846R0《ADL and Function Templates that are not Visible》將這個規則擴展到了樣板 :

namespace N {
    struct A {};
    template <typename T>
    int f(T);
}

auto x = f(N::A {});        // OK since C++ 20, error before C++ 20

2. 複製建構子中的 const

在 C++ 20 之前, 帶有參數為帶有 const 的複製建構子和不帶有 const 的複製建構子是不相容的 :

struct A {
    A(A &);
};
template <typename T>
struct W {
    T t;
    W(const W &) = default;
};

W<A> w;     // Error

C++ 20 提案 P0641R2《Resolving Core Issue #1331 (const mismatch with defaulted copy constructor)》修正了這個問題, Code 2 在 C++ 20 中可以通過編碼.

3. 樣板存取私用成員

《【C++】竊取私用成員》中, 我們講述了如何通過樣板來竊取類別的私用成員. 現在這個問題的討論範圍被擴大了, 主要集中在下面的程式碼上 :

template <typename T>
struct traits;

class A {
    class B {};
};

template <>
struct traits<A::B> {
    // ...
};

根據 C++ 17 標準, 巢狀類別 BA 的私用成員, 所以外部不應該存取到它. 但是如果存取不到它, 一些和 A::B 有關的特性萃取是無法實作的. 因此, GCC 和 MSVC 都允許 Code 3 中的寫法, 而 Clang 則會擲出編碼錯誤. 經過討論之後, C++ 20 提案 P0692R1《Access Checking on Specializations》修改了標準, 允許了 Code 3 中的寫法. 因為這種寫法雖然給予了樣板特殊的存取權限, 但是它並沒有破壞現有代碼的合法性, 特別是在 SFINAE 中, B 仍然是不可訪問的.

4. typename 的省略

C++ 20 提案 P0634R3《Down with typename!》為 C++ 帶來了幾種可以省略掉 typename 的新地方 :

  1. 函式的回傳型別, 包括尾置回傳型別;
  2. 函式的參數列表, 包括函式指標中的參數列表;
  3. usingtypedef 中;
  4. 轉型運算子樣板參數列表部分.

有一種特別的情況,

template <typename T>
void f(int i) {
    T::x * i;
}

中的 T::x * i 是表達式, 為 T::x 前增加 typename 宣告反而會引起編碼錯誤.

5. 樣板參數中的類別

C++ 20 提案 P0732R2《Class Types in Non-Type Template Parameters》提出, 讓非型別樣板參數也支援類別. 這些類別必須滿足

  1. 字面值型別;
  2. 基礎類別和成員的三路比較運算子 (《【C++ 20】三路比較運算子 (operator<=>)》) 回傳的結果為 std::strong_ordering;
  3. 沒有成員被 mutable 或者 volatile 標識;
  4. 若存在被 = default 標識的三路比較運算子, 那麼其必須是公有的.

另外, 《C++ 17 特性合集 (二)》第 2 節中提到了 C++ 17 為非型別樣板參數增加了 auto 的推導, 這個推導在 C++ 20 中同樣支援對類別引數的推導.

另一份 C++ 20 提案 P1907R1《Inconsistencies with non-type template parameters》中提出, 既然樣板參數已經支援了類別, 那麼也應該支援指向類別的指標. 因此, C++ 20 的樣板參數中支援放入類別指標或者類別參考.