ホームに戻る
出典 :
ジェネリックプログラミング - Wikipedia
関連 :
[C++]関数オーバーロードとデフォルト引数 [C++]コンテナ [C++]型推論
目次 :

ジェネリック(汎用)プログラミングとは

特定のデータ型に依存しない、抽象的・汎用的な処理を実装すること。共通のロジックを複数のデータ型に適用でき、データ型に縛られない本質的な処理を実装できる。
このように定義された関数を 汎用関数 (Generic Function)と呼ぶ。C++、Java、C#(.NET)などのモダン言語で用いることができる。
(言語によって「テンプレート」、「ジェネリクス」と呼称が異なるが、本質的には同等である。)

ジェネリックプログラミングを用いない場合の例

画像

ジェネリックプログラミングを用いた場合の例

画像

汎用関数の定義

C++ (テンプレート)

画像

C#

C#で定義した汎用関数はC++(CLI)でも用いることができる。但しC++形式の汎用関数とは互換性が無い。
画像

汎用関数のオーバーロード

標準的な処理を汎用関数として定義しておき、特定の型に対してのみ異なる処理を行う場合は、必要に応じてオーバーロードを行うことができる。
特定の型に関してオーバーロードを行った場合、オーバーロード関数によって汎用関数が隠蔽(オーバーライド)される。

C#における汎用メソッドのオーバーロード

※この単元は正確でない可能性があります。

汎用メソッドを特定の型向けにオーバーロードを行った場合、C++とは異なり、汎用メソッドが優先して呼ばれる模様(要追加調査)。
即ち、汎用メソッドがオーバーライドされない。このため、実引数の型を判別して個別メソッドに振り分ける作業が必要となる。
(回避手段が存在する可能性あり?)
// 汎用メソッド Hoge() private static byte[] Hoge(T[] args) { // T の型に応じた、個別のオーバーロードメソッドを呼びなおす // (引数を個別型にリキャスト) if ( typeof(T) == typeof(UInt16) ) { return Hoge((UInt16[])(object)args); } if ( typeof(T) == typeof(UInt32) ) { return Hoge((UInt32[])(object)args); } if ( typeof(T) == typeof(UInt64) ) { return Hoge((UInt64[])(object)args); } if ( typeof(T) == typeof((UInt64, byte)) ) { return Hoge(((UInt64, byte)[])(object)args); } // オーバーロードされていない型に対する処理 : } // 特定型向け Hoge() (オーバーロード) private static byte[] Hoge(UInt16[] args) { : } private static byte[] Hoge(UInt32[] args) { : } private static byte[] Hoge(UInt64[] args) { : } private static byte[] Hoge((UInt64 val, byte len)[] args) { : }
上記コード例のように typeof を用いることで、実引数の型(Type 型オブジェクト)を取得することができる。
ここで typeof(T) は定数式ではないため、switch - case 節で用いることはできない(回避手段あり?)
汎用型変数(上記における args )をリキャストする際は、上述のように (object) でキャスト後、目的の型でリキャストする。
また、既存のオブジェクトの型情報は GetType() メソッドで取得することができる。
(GetType() メソッドは Object から派生するすべての型で用いることができる。数値型では使用できない?要調査)
: var foo = args[0]; : // (実際の型が不明な) foo オブジェクトの型を取得 foo.GetType(); :

汎用クラス (Generic Class)

特定の型に依存しない汎用的な論理を含んだクラスを定義することができる。これを 汎用クラス と呼ぶ。
汎用クラスのインスタンスを生成する際に操作対象の型を指定する必要がある。汎用クラスのメンバ関数は自動的に汎用関数となる。
// 汎用リスト(単方向) // 操作対象(保持する値)は Data_t 型 template <class Data_t> class List_t { private: Data_t data; //< データ List_t* next; //< 次の要素 public: // メンバ関数宣言 (この時点では template キーワードは不要) List_t(Data_t d); //< コンストラクタ(ここでは宣言のみ) void add(List_t* node) { node->next = this; next = 0; } //< 自身の前に要素を挿入 List_t* getnext() { return next; } //< 次の要素へのポインタを取得 Data_t getdata() { return data; } //< 値を取得 } // List_t のコンストラクタ定義 // クラス定義の外なので、template キーワードを付与 template <class Data_t> List_t<Data_t>::List_t(Data_t d) { data = d; next = 0; } : // List_t 型変数 start を生成 // (保持対象として char 型を指定) List_t<char> start('a');
C++のSTL(標準テンプレートライブラリ)はその名の通り汎用クラスとして定義されており、多様な型のデータを共通の手法で管理できる。コンテナが代表的。