C++primer第16章.テンプレートと汎用プログラミング-テンプレートの定義(1)

5832 ワード

同じ形式の関数について、パラメータのタイプが異なるだけでは、異なるパラメータテーブルの関数にコピーを書き直すのは面倒です.テンプレートメタプログラミングでは、汎用的な方法で関数を書くことができますが、テンプレートと演算子の再ロードの威力は驚くべきもので、コードの多重性を大幅に向上させます.可読性も向上しています.
汎用プログラミングはC++の最も重要な性質の一つといえ,オブジェクト向けの特性を強調している.テンプレートの使い方をご紹介します
1.関数テンプレート
関数のテンプレートは次のとおりです.
template int compare(const T& v1,const T& v2)

{

 if(v1v2)return 1;

 return 0;

}

templateキーワードの後にテンプレートパラメータのリストがあります.テンプレートパラメータが含まれています.これらのパラメータに基づいてテンプレートのインスタンスを決定します.
テンプレートを関数と見なすと、テンプレートパラメータがテンプレートのパラメータになります.
この例では,タイプ名Tを定義し,次にすべてのTが関数コンテキスト内のすべてのTを表す.
関数パラメータテーブルには2つのT参照タイプのパラメータがあり、それらの比較結果に基づいて対応する値を返します(Tタイプのオブジェクトが比較演算子または比較演算子の再ロードを許可することを前提とします).
関数テンプレートの具体的なインスタンス化プロセスはコンパイル中に発生し、コンパイラが関数テンプレートの呼び出しを検出すると、関数パラメータのタイプがチェックされ、対応するインスタンスが検索されます.たとえば、compare(1,2)を呼び出すと、コンパイラはこれが2つのint定数であることを発見し、コンパイルはTをintのバージョンに置き換え、compare(1,2)にこのバージョンのインスタンスを呼び出すようにします.
テンプレートパラメータには、タイプテンプレートパラメータと非タイプテンプレートパラメータが含まれます.キーワードtypenameを使用すると、次に表示されるパラメータ名Tを表すタイプ名が指定されます.タイプパラメータではなく、キーワードclassやtypenameではなく特定のタイプ名で指定された値を表すより明らかな用途があります.
たとえば
template int compare(const char (&p1)[N] , const char(&p2)[M])

{

 return strcmp(p1,p2);

}

compare(「hi」「mom」)を使用すると、の場合、テンプレートはN=3、M=4のバージョンをインスタンス化します(文字列の末尾に空の文字が終端としてあるため)
/*パラメータが配列ポインタの場合、配列の長さからテンプレートの例を判断することはできませんが、パラメータが配列参照であれば可能です.パラメータの長さは実パラメータと一致しなければなりません.理由は不明ですが、Effective C++で*/
非タイプテンプレートパラメータは、整形またはオブジェクトまたは関数タイプを指すポインタまたは参照(すなわち、私がどのようなオブジェクトとどのような関数を使用したかを伝える情報)であってもよく、関数パラメータテーブルのパラメータの様々な情報からテンプレートのインスタンスを判断しようとすると、非タイプの整形パラメータにバインドされた実パラメータは定数式でなければなりませんが、ポインタまたは参照(定数オブジェクトまたは関数を指す)にバインドされた実パラメータは、コンパイル中にその実パラメータが存在する静的生存期間を持つ必要があります.
/*非タイプテンプレートパラメータについてはポインタまたは参照が可能で、私はそれがどのような問題を解決したのかよく理解していません.結局、関数パラメータの伝達を利用しても効果が得られます.テンプレートの具体的なインスタンス化によって、異なるテンプレートパラメータに全く異なる実行コードが許可される可能性がありますが、これは別の異なる関数を書き直すことと区別されません.つまりタイプに関係なく破壊され、テンプレートの特徴は現れず、これはピット後に記入*/
関数テンプレートにはconstexprとinlineキーワードがあります.この3つはコンパイル期間の特性で、コンパイラが管理します.
テンプレートの大きな利点は、タイプに関係のないコードを記述できることです.例えば、intタイプの2つの量を比較することができます.unsigned、long、doubleはすべて可能です.つまり、このコードの論理はタイプに関係なく、「」演算子をサポートしている限り、異なるインスタンスで使用できます.サポートされていない場合、コンパイルエラーが発生します.
テンプレートのエラーレポート:
通常、コンパイラは3段階に分けてエラーを報告します.
1.テンプレート自体をコンパイルする場合、クラスパラメータと非クラスパラメータが確定していないため、多くのエラーの可能性がある場所では、コンパイラはエラーを報告しません.この場合、発見されたエラーは一般的に、セミコロン、変数名、括弧などのparserエラーなどの基礎的な構文エラーです.
2.コンパイラがテンプレートの使用に遭遇した場合、コンパイラは呼び出し関数の実パラメータ数とタイプが一致しているかどうかをチェックします.一致しない場合は、対応するテンプレートインスタンスがないことを示します.
3.コンパイラがテンプレートのインスタンスを決定し、それをインスタンス化すると、このときタイプに関するエラーやC++標準で禁止されている操作などが発見されます.このとき、すべての構文エラーが本当に見つかりますが、コンパイラがインスタンス化を管理する方法は異なり、リンク時に報告される可能性があります.
2.クラステンプレート
関数テンプレートとは異なり、クラステンプレートは関数の実パラメータからテンプレートパラメータを推定してインスタンス化するのではなく、対応するテンプレートパラメータをカッコで直接与えてインスタンス化する
クラステンプレートの定義
templateclass Blob

{public:

 typedef T value_type;

 typedef typename std::vector::size_type size_type;//        vector       size_type          size_type   ,    

 Blob();//    

 Blob(std::initializer_list il);//       initializer_list    Blob,  Blob           T     initializer_list   il

 size_type size() const{ return data->size(); }

 bool empty const{ return data->empty(); }

 void push_back(const T& t) { data->push_back(t); }

 void pop_back();//   ,     

 T& back();

 T& operator[](size_type i);//  "[]"   

private:

 std::shared_ptr<:vector>> data;//         ,  Blob      vector      

 void check(size_type i, const std::string& msg) const;//  data[i]    ,      error message,  msg   
}

1つのテンプレートに別のテンプレートが使用されている場合は、パラメータ付きの内層テンプレート、すなわち所定のインスタンスをパラメータとして外層テンプレートに渡します.内層テンプレートのパラメータを外層テンプレートに簡単に渡すのではなく、外層テンプレートに参照します.
メリットは、1.外層テンプレートの実例化の過程で、内層テンプレートを先に検査し、内層テンプレートを実例化した後、外層を実例化し、先外層後内層を回避し、不要な潜在的な問題をもたらす.パッケージの考え方を体現して、内層テンプレートのパラメータとして、デフォルトは外層テンプレートによって直接見るべきではありません.そうする必要がない限り、外層テンプレートのパラメータの最良は内層の例だけで、内層のインスタンス化の具体的な実現を含まない
クラステンプレートのメンバー関数
各クラステンプレートインスタンスには独自のバージョンのメンバー関数があるため、クラス定義以外のメンバー関数を定義するにはtemplateキーを付ける必要があります.
template void Blob::check(size_type i, const std::string &msg) const

{

}

構文を解析します.template Blob::文は役割ドメインがあるインスタンスであることを示しています.このインスタンスはパラメータTを参照として、voidはこの関数の戻り値を表し、checkは関数名を説明します.
一見文法的に違和感があるかもしれませんが、一般的に関数はタイプヘッダを返しますが、テンプレートにとってはコンパイラ特性(C++の特性の多くはコンパイラ特性であり、Cにpluginを1つ追加し、中間層を複数追加したと考えられますが、LLVMでもできます)なので、templateヘッダがテンプレートパラメータを示す必要があります.これは同時にテンプレートの役割ドメインの問題を解決し、クラステンプレートの外でクラステンプレート名を使用する場合、templateキーワードとテンプレートパラメータリストで先頭に立って、テンプレートのインスタンスの参照を示します.では、関数を定義するときにテンプレートを使用してタイプを返すことができます.このテンプレートのパラメータはすでに与えられているため、例えば:
template BlobPtr BlobPtr::operator++(int)

{
 BlobPtr ret= *this;
 ++(*this);
 return ret; 
}

以上の構文は、関数の戻りタイプBlobPtr、関数が存在するドメインBlobPtr、関数は++記号を再ロードします.
関数の役割ドメイン内に入った後、テンプレートの実パラメータTを再強調する必要はありません.他のテンプレートのインスタンスまたはこのテンプレートの他のインスタンスが返されるタイプでない限り、デフォルトではテンプレートパラメータが与えられていない場合、このテンプレートのパラメータはTです.
不思議な考え:
インスタンスのメンバー関数に同じテンプレートの別のインスタンスタイプの値を返す場合は、次のようなことはできません.
インスタンスはテンプレート自体も表示されず、他のインスタンスも表示されず、このインスタンスしか表示されません.関数を定義するときは、まずインスタンス化し、次に
クラステンプレートと友元の宣言について
クラステンプレートにテンプレート以外の友元を生命すると、この友元はすべてのクラステンプレートインスタンスの友元権限を有します.
テンプレートパラメータを直接指定して、特定のクラステンプレートインスタンスに友元権限を持たせることもできます.
テンプレートパラメータTを友元としてもよい
クラステンプレートの異なるインスタンス間には意味的なつながりはありません.つまり、完全に異なる2つのクラスに属している場合、静的メンバーがあれば、異なるインスタンス間でも共有されません.