あるコードを書いていて,Visual C++ 2008ではコンパイルが通るのに,g++では通らないケースで悩む.Visual C++ 2008はtypenameキーワードまわりが緩く,g++では付け忘れを大量に指摘されるのが常だ.そんなVisual C++ 2008のぬるま湯に浸かっているためか,今日は以下のようなコードがコンパイル出来なくてびっくりした.
template <class T>
class base
{
public:
T var;
};
template <class T>
class derived : public base<T>
{
public:
void set(const T& x)
{
var = x; // error: `var' undeclared.
}
};
int main(int argc, char *argv[])
{
derived<int> x;
x.set(2);
return 0;
}
Visual C++ 2008ではエラー・警告無しだが,g++ 3.4では,”error: `var’ undeclared” というエラーが,派生クラス (derived) の var = x; という箇所で発生する.変数varは基底クラスbaseでpublicメンバとして定義されており,derivedはbaseをpublic継承しているので,deriveクラス内部からvarにアクセスできるのは,当然のはず.それがg++では,認められない.
こういうエラーは検索キーワードを見つけるのが難しいが,ほどなく C++ Template FAQ というページに辿りつく.これによると,テンプレート化されている派生クラスが,同じくテンプレート化されている基底クラスのメンバをアクセスするには,this->var = x; または,base<T>::var = x; みたいにしなければならない.このルールは,メンバ変数,メンバ関数のどちらにも当てはまるらしい.テンプレート化されていなければ,こういうことは起きないし,Visual C++では問題なくコンパイルが通っていたので,ちょっと驚きだった.
C++のコードは,フィーリングで何となく書けているけど,正確なコードを書くのは大変なんだなぁと改めて実感.