[C++] テンプレートの特殊化 ================================================================================ テンプレートの指定で、Java のように、あるクラスを継承したクラスのみに限定する、 ということができる。 Javaの例: class MyClass<T extends Number> 「テンプレートの特殊化」というものを使って実現できる。 でも、かなり面倒くさい。 まずは汎用的なテンプレート関数を宣言する。 template<class T> // (4) void print(T& t) { テンプレートの特殊化ということで、特定の型に対するテンプレート関数を宣言する。 template<> // (5) void print<Base> (Base& t) { 派生クラスのオブジェクト d を引数に渡すときは、基本クラスの型として渡す。 print(*(dynamic_cast<Base*> (&d))); // (10) これで、派生クラスのオブジェクト d に対して、Base 型のテンプレート関数が使われる。 もちろん、単に print(d); // (8) とした場合は、汎用的なテンプレート関数が呼び出される。 □ generic_sample.cpp --- #include <iostream> using namespace std; class Base { // (1) public: virtual void print() { cout << "Base" << endl; } }; class Derived: public Base { // (2) public: void print() { cout << "Derived" << endl; } }; class Other { // (3) public: void print() { cout << "Other" << endl; } }; template<class T> // (4) void print(T& t) { cout << "G: "; t.print(); } template<> // (5) void print<Base> (Base& t) { cout << "B: "; t.print(); } //template<> // (6) //void print<Derived>(Derived& t) { // cout << "D: "; // t.print(); //} int main() { Base b; print(b); // (7) Derived d; print(d); // (8) print(*((Base*) (&d))); // (9) print(*(dynamic_cast<Base*> (&d))); // (10) Other o; print(o); // (11) // print(*((Base*) (&o))); // (12) // 実行時エラー // print(*(dynamic_cast<Base*> (&o))); // (13) // コンパイルエラー return 0; } --- □ 実行結果 --- B: Base <- (7) G: Derived <- (8) B: Derived <- (9) B: Derived <- (10) G: Other <- (11) --- (1) 基本クラス Base class Base { // (1) ... }; (2) 派生クラス Derived 基本クラス Base を継承し、print() 関数をオーバーライドする。 class Derived: public Base { // (2) ... }; (3) 関係ないクラス Other Base クラスとも、Derived クラスとも関係のないクラス。 class Other { // (3) ... }; (4) テンプレート 汎用のテンプレート関数。引数は参照で受け取る。 template<class T> // (4) void print(T& t) { ... } (5) テンプレートの特殊化 Base 型で受け取るテンプレート関数。 template<> // (5) void print<Base> (Base& t) { ... } (6) テンプレートの特殊化 Derived 型で受け取るテンプレート関数。今回は、コメントアウトしている。 //template<> // (6) //void print<Derived>(Derived& t) { ... //} 上記のコードを有効にしておくと、実行結果は次のようになる。 --- B: Base <- (7) D: Derived <- (8) B: Derived <- (9) B: Derived <- (10) G: Other <- (11) --- (7) 基本クラスのオブジェクトをプリント print(b); // (7) 特殊化によって、(5)のテンプレート関数が使われる。 (8)-(10) 派生クラスのオブジェクトをプリント print(d); // (8) 特殊化は、あくまでも、そのクラス(型)が対象なので、その型の派生クラスというのは関 係ない。したがって、これは、あくまでも汎用のテンプレート関数を使う。 print(*((Base*) (&d))); // (9) print(*(dynamic_cast<Base*> (&d))); // (10) 派生クラスのオブジェクトを、基本クラスの型にキャストしてしまえば、基本クラスを使 った特殊テンプレートが利用できる。 キャストの方法としては、(9)のように、C言語のキャスト、dynamic_cast を使う 2 つの 方法があるが、dynamic_cast を使うほうがよい。これは、つぎの説明のように、基本ク ラスとは派生関係にないクラスのオブジェクトをキャストして、特殊化したテンプレート 関数を使わせたいときに、C言語のキャストでは、実行時までエラーがわからないが、 dynamic_cast であれば、コンパイル・エラーになるからである。 (11) 関係ないクラスのオブジェクトをプリント print(o); // (11) 汎用のテンプレート関数を使う。 // print(*((Base*) (&o))); // (12) // 実行時エラー このコードは、実行時にエラーになる。 // print(*(dynamic_cast<Base*> (&o))); // (13) // コンパイルエラー このコードは、次のコンパイルエラーになる。 --- In function `int main()': error: cannot dynamic_cast `&o' (of type `class Other*') to type `class Base *' (source type is not polymorphic) Build error occurred, build is stopped ---