C++ プログラミングガイド

テンプレート関数のフレンド宣言

テンプレートは、使用前に宣言されていなければなりません。フレンド宣言では、テンプレートを宣言するのではなく、テンプレートの使用を宣言します。フレンド宣言の前に、実際のテンプレートが宣言されていなければなりません。次の例では、作成済みオブジェクトファイルをリンクしようとするときに、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<<(std::ostream&, const array<T>&);
};
#endif