template class の static メンバの件
研究室のツールを gcc 4 だとコンパイルできないという問題があって、おかげで演習3が進まない。これは悪いことをした。それはそれとして、このままなのはマズイので、研究室で先輩と一緒にデバッグ。というか、コンパイルはできるんだがリンクで失敗するんだよね。すごく久し振りに、C++ の、しかもマニアックな部分をいじくる。
問題となる部分は、template クラスにおける static メンバの実体がないと怒られる。
template <typename T> class C { public: static string s; }; template<> string C<int> s; template<> string C<double> s; int main() { C<int>::s = "int"; C<double>::s = "double"; }
インスタンス化させた template クラス分、実体を作っておかないとマズイ。と思うわけだ。少なくとも、 gcc 3.4.x ではこれで通るのだ。ちなみにあとからわかったことだが、上記のコードは gcc 4.0.x でも、何事もなかったようにコンパイルに通った。問題のアプリケーションは通らないのだが。実はこれが問題の本質じゃなかったのかもしれない。
それはさておき、実は以下のようなコードを書いても大丈夫だということが発覚した。
template <typename T> class C { ... }; template <typename T> string C<T> s; ...
少し私にとって衝撃的である。s の実体がいくつ必要かわからないのに、こんなんでいいのか。こんなんでいいって誰が言ったのか、というかどう書けばいいのか誰も教えてくれない。それが C++。あー、こんな書き方あったのかよと知った日。そんな日。
s の実体がいくつ必要か(つまり、C
と思ったが、そこまで問題でないことが直ちに分かった。つまり、分割された両方のファイルで、template
ちなみに、このような記法は当初 gcc 4.0.x で追加されたと思われたが、実は gcc 3.4.x でも、gcc 3.2.x でも動くことが分かった。そんな・・・。なわけで、これが当該アプリケーションの本当の問題だったかどうかは、結局分からずじまいだったのだが、どういうわけかこの修正でコンパイルが通るようになった。ついでに、cl7 (VC)でも、cl8 でも余裕で通る。単に知らなかっただけなのか。Stroustrup 本の template の章をざっと見たが、該当する記述は見つからない。
というわけで、上記のようなプログラムの最善策は・・・。
template <typename T> class C { public: static string s; }; template <typename T> string C<T>::s;
これを、各ソースファイルに include すればいいということだ。え、こんなんでいいの?というのがその場にいたみんなの感想だったので、まぁなんというか・・・。何度も言う。C++ はすでに破綻している。