テンプレートは、使用前に宣言されている必要があります。フレンド宣言では、テンプレートを宣言するのではなく、テンプレートの使用を宣言します。フレンド宣言の前に、実際のテンプレートが宣言されている必要があります。次の例では、作成済みオブジェクトファイルをリンクしようとするときに、operator<< 関数が未定義であるというエラーが生成されます。その結果、operator<< 関数はインスタンス化されません。
array.h // operator<< 関数に対して未定義エラーを生成する #ifndef ARRAY_H #define ARRAY_H #include <iosfwd> template<class T> class array { int size; public: array(); friend std::ostream& operator<<(std::ostream&, const array<T>&); }; #endif array.cc #include <stdlib.h> #include <iostream> template<class T> array<T>::array() {size = 1024;} template<class T> std::ostream& operator<<(std::ostream& out, const array<T>& rhs) {return out <<’[’ << rhs.size <<’]’;} main.cc #include <iostream> #include "array.h" int main() { std::cout << "creating an array of int... " << std::flush; array<int> foo; std::cout << "done\n"; std::cout << foo << std::endl; return 0; } |
コンパイラは、次の宣言を array クラスの friend である正規関数の宣言として読み取っているので、コンパイル中にエラーメッセージを表示しません。
friend ostream& operator<<(ostream&, const array<T>&); |
operator<< は実際にはテンプレート関数であるため、template class array を宣言する前にこの関数にテンプレート宣言を行う必要があります。しかし、operator<< はパラメータ type array<T> を持つため、関数宣言の前に array<T> を宣言する必要があります。ファイル array.h は、次のようになります。
#ifndef ARRAY_H #define ARRAY_H #include <iosfwd> // 次の 2 行は operator<< をテンプレート関数として宣言する template<class T> class array; template<class T> std::ostream& operator<<(std::ostream&, const array<T>&); template<class T> class array { int size; public: array(); friend std::ostream& operator<< <T> (std::ostream&, const array<T>&); }; #endif |