テンプレートは、型、定数値、テンプレート、およびパックによってパラメーター化された宣言の集合です。特殊化は、C++の名前探索、型検査、オーバーロード解決、および制約の規則に従って形成されます。テンプレートはテキスト置換ではありません。
テンプレートパラメーター #
型パラメーターは型を受け取り、定数テンプレートパラメーターは構造的な定数値を受け取り、テンプレートテンプレートパラメーターは互換性のあるテンプレートを受け取ります。デフォルトにより、省略された引数を指定できます。パラメーターパックは、0個以上のパラメーターまたは引数を表します。
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 {};クラステンプレートまたはエイリアステンプレートは、型、定数、テンプレート、およびパックのパラメーターを持つことができます。関数テンプレートでは推論が追加されます。推論されるパラメーター位置にある引数は呼び出し側の引数から推論されますが、非推論パラメーターは指定するか、別の場所から取得する必要があります。
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 #
関数、クラス、変数、エイリアス、およびメンバーテンプレートには、それぞれ異なるインスタンス化規則があります。
#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)は、コンストラクター、集成体推論候補、またはユーザー定義の推論ガイドからクラステンプレートの引数を選択します。クラステンプレート名を明示的な引数なしで使用した場合に適用されますが、関数テンプレートには適用されません。
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 宣言は、別の場所で提供されたインスタンス化を使用できる翻訳単位で暗黙的なインスタンス化を抑制します。
// 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 で閲覧・コメントする(投稿にはログインが必要です)