2020年5月20日水曜日

C++ Templates - The Complete Guide, 2nd 読書メモ 2章 クラステンプレート

C++ Templates - The Complete Guide, 2ndの2章「クラステンプレート」の読書メモ

スタックの実装を例にクラステンプレートについて解説している.


クラステンプレートの宣言


関数テンプレートと同様に,templateの後にテンプレート仮引数を並べ,クラス宣言を書く.

template <typename T>
class Stack {
  ...
};

クラステンプレート内では,Tを型として利用できる.

コピーコンストラクタなどを書く場合,次の2通りの書き方があるが,敢えて書くと意味があるように思わせるので,前者の方が良い.

Stack(const Stack &);
Stack(const Stack<T> &);

メンバ関数の実装


クラステンプレートのメンバ関数を実装する方法として,クラスの外側で定義する方法とクラス内で定義する方法が紹介されている.

ついでに,例外安全についても触れていて,Exceptional C++が紹介されている.

クラステンプレートの利用


基本的には,クラステンプレートを利用する場合は型を明示する必要があるが,C++17では型を省略する方法が追加され,後ほど解説する,とある.

また,呼び出されたテンプレート(メンバ)関数のみがインスタンス化される,とある.

friend


フレンド関数を定義するには,クラス内で宣言してしまう方法と,後から別途宣言する方法が2つ紹介されている.

template <typename U>
friend std::ostream & operator<<(std::ostream &, const Stack<U> &); // 別途非メンバ関数として定義する

template <typename T>
class Stack; // 前方宣言
template <typename T>
std::ostream & operator<<(std::ostream &, const Stack<T> &);

template <typename T>
class Stack {
    friend std::ostream & operator<< <T>(std::ostream &, const Stack<T> &);
};

テンプレートの特殊化


template <>として,クラス名の後に具体的な型を指定して定義することで,特定の型の場合について専用の実装を用意することができる.

例としては,std::vector<bool>など.

例えば,typename Tに対して,T *,とポインタ型にするような部分的な特殊化も可能.

デフォルト実引数


関数テンプレートと同様に,テンプレート仮引数にデフォルト実引数を指定することが可能.

タイプエイリアス


typedefのように型の別名を定義する方法として,usingによるエイリアス宣言が紹介されている.

typedefよりも = でつなぐ分,読みやすい,とも.

また,エイリアスはテンプレートにもできる.

template <typename T>
using DequeStack = Stack<T, std::deque<T>>;

C++14以降では,標準ライブラリでは 型とレイトである型から他の型を取り出す場合,今まではA::typeとしていたのを,A_tというようなエイリアスが用意された.

クラステンプレート実引数推論


C++17から,初期化時の実引数からクラステンプレートの型を推論できるようになった.使い方次第では便利なのだろうけれど,使いこなせない気がする.

文字列を利用して推論する場合の注意点についても触れている.コンストラクタが参照を受け取るようになっていると,文字列から推論しようとするとconst char [x]のような型になってしまうが,値渡しにしていると,const char *になる.

推論ガイド(deduction guide)についてもサラッと触れている.

テンプレート化された集成体


ユーザー定義または継承したコンストラクタを持たず,privateやprotectedな非staticメンバを持たず,仮想関数,仮想またはprivateまたはprotectedなベースクラスを持たないクラスまたは構造体をテンプレートにすることもできる.

0 件のコメント:

コメントを投稿