templateクラスのエラー

前に引数に任意の型を代入できる行列クラスを実装したときにおきたエラー。

/**
 * @file class.h
 */
template<class T>
public class Class{
public:
  Class();
  ~Class();

  T func(){
    return t;
  }
private:
  T t;
};

このテンプレートクラス内のメンバ関数の内容(今回の場合はfunc())をヘッダではなくcppファイルの方にかくとリンクのエラーを返すのです。

このエラーは仕様らしく、たくさんの人が詰まったことがあるエラー(?)らしい。
コンパイラがtemplateを解釈する方法にはinclusion-modelとseparation-modelの二つがあってVisualC++は前者を採用しているみたい。
inclusionモデルとは簡単に言うとtemplateのメンバ関数をヘッダに、separationモデルは実装をcppの方に書く、というモデルだそうです。
要はVC++でcppの方に実装は難しそうですよ。
一応方法としてはテンプレートの実体化をcppで明示的に行う方法があるみたいです。

/**
 * @file class.h
 */
template<class T>
public class Class{
public:
  Class();
  ~Class();

  T func();
private:
  T t;
};
/**
 * @file class.cpp
 */
Class<T>::Class(){}

Class<T>::~Class(){}

T Class<T>::func(){return t;}

// 実体化したいクラス(型)を指定する。
template class Class<float>
template class Class<double>

のように実装すればいけるみたいです。
が…それはtemplateのクラスの型がすでに分かっている場合にしか適用できないわけですよ。上記の場合はfloatやdouble以外をいれるとエラーを返すわけですね。
だからどんな型でも対応できるようにするためにはヘッダにかかなければいけない。その場合は実装を隠蔽できない。逆に型を限定する場合はcppに実装することができる、というわけです。

まあどっちをとるかは実装する内容に依存するわけですが…難しいですね。。。
そろそろC++コンパイラが実際になにをやってるのか勉強しようかなぁ。