C++ 範本基礎

最後更新: 2021-05-03 19:04:55 +0800 +0800
原文以英文撰寫。您正在閱讀AI翻譯版本。

範本是由型別、常數值、範本與參數包參數化的宣告族。特化會在 C++ 名稱查找、型別檢查、多載解析與約束規則下形成;範本不是文字替換。

範本參數 #

型別參數接受型別,常數範本參數接受結構化常數值,而範本範本參數接受相容的範本。預設值可提供省略的引數。參數包代表零個或多個參數或引數。

cpp
template <class T, std::size_t N = 16>
struct Buffer;

template <auto Value>
struct Constant;

template <template <class...> class Container, class T>
using one_element_container = Container<T>;

template <class... Ts>
struct TypeList {};

類別範本或別名範本可以具有型別、常數、範本與參數包參數。函式範本額外支援推導:出現在可推導參數位置的引數會從呼叫引數推斷,而不可推導參數則必須提供,或從其他地方取得。

cpp
template <class T>
T maximum(T left, T right);

auto a = maximum(1, 2);       // T is int
auto b = maximum<double>(1, 2.5);

明確的範本引數位於一般呼叫引數之前。推導不會使用函式回傳型別,因為呼叫結果可能被捨棄,而且多載解析需要在得知結果前先取得候選型別。

範本類別與 CTAD #

函式、類別、變數、別名與成員範本具有不同的具現化規則。

cpp
#include <type_traits>

template <class T> T identity(T value) { return value; } // function
template <class T> struct Box { T value; };               // class
template <class T> inline constexpr bool is_box = false;  // variable
template <class T> using remove_cvref_t =                 // alias
    std::remove_cvref_t<T>;

struct Store {
    template <class T> void put(T&& value);               // member
};

類別範本引數推導(CTAD)會根據建構函式、聚合推導候選項或使用者定義的推導指南來選擇類別範本引數。當使用類別範本名稱而未指定明確引數時會套用;不適用於函式範本。

cpp
template <class T>
struct Pair { T first; T second; };

template <class T, class U>
Pair(T, U) -> Pair<std::common_type_t<T, U>>;

Pair values{1, 2}; // Pair<int> through the deduction guide

當建構函式參數型別無法表達預期的儲存型別時,請撰寫推導指南。如果在 API 邊界明確寫出型別能更清楚地表達所有權、單位或縮窄策略,請不要依賴 CTAD。

具現化與可見性 #

當需要某個特化時會發生隱含具現化,但仍受具現化點規則約束。相關範本定義必須在該點可達,這也是函式與類別範本定義慣例上位於標頭檔中的原因。

明確具現化定義會產生特化;extern template 宣告會抑制翻譯單元中的隱含具現化,而該翻譯單元可以使用其他地方提供的具現化。

cpp
// widget.hpp
template <class T>
class Widget {
public:
    void draw();
};

extern template class Widget<int>;

// widget.cc, after the definition is visible
template <class T>
void Widget<T>::draw() {}

template class Widget<int>;

明確具現化是建置時的控制機制,不是讓每個所需特化保持有效的替代方案。請在使用前讓宣告保持可見,並在編譯器必須具現化範本的所有位置讓範本定義保持可見。

評論

在 GitHub 上閱讀或評論(發表評論需要登入)