Entry

プログラミングメモ - C++ テンプレートクラスのヘッダ構成

2010年10月02日

よく知られている話なので,いちいち書くこともないけれども,一応書いておきます。

ご存知だと思うけれども,テンプレートクラスを使う場合,宣言のみをヘッダとして公開して実装をローカルに作る(リンク時の依存関係にする)ことはできません。つまり,テンプレートクラスを利用するソースは,宣言も実装コードもそれを使うプログラムのソースに入ってないといけないということです(ソースに入っているというのは,「コンパイル時に入っている」ということ,インクルードすれば当然ソースに含まれることになる)。

どうしてかというと,テンプレートクラスの宣言と実装は,それだけで完結したコード(オブジェクトコード)を生成できないからです。直感的にも分かると思うけれども,テンプレートはテンプレート引数を伴って,初めてオブジェクトコードとしてひとり立ちすることができます。template<typename T> Foo と宣言された Foo<T> は,Foo<double> として使われるか Foo<int> として使われるか,はたまた別のテンプレート引数を使われるか,テンプレートの中だけでは分かりません。テンプレートを使うプログラムと一緒にコンパイルされないと,オブジェクトコードを生成できないというわけです。

とゆことで,C++ でテンプレートクラスを書く場合,通常のヘッダとソースコードのように,別々に管理することはできません。ソースコードの構成方法には,大きく分けて次の3種類があります。

  • ヘッダにクラス宣言と実装をすべて含めてしまう。
  • export キーワードを使って実装と宣言を分ける。
  • 実装と宣言のヘッダを分けて書き実装から宣言をインクルードする。

最初の方法はもっとも簡単だけれども,実装と宣言を分けて書くメリットが損なわれます。テンプレートの場合,ヘッダと実装を分けるメリットはあまりないんですけれど,インターフェイスだけ「わかりやすく」公開できる点で,個人的には分割して管理した方がいい気がします。

次の方法は,最初の方法の間逆で,実装ファイルとヘッダファイルをかっちりと分ける方法です。冒頭でヘッダとソースは別々に管理できないと書いたけれども,export キーワードを使うと似たようなことができるんですね。もっとも,export キーワードをサポートする処理系は,現在とても少ないです。ソースの可搬性を考慮しないならば,もっとも良い選択肢ですけれど,通常はそうも言ってられませんよね。

つことで,あたしのお勧めは,最後のようにヘッダをふたつ書く方法です。

やることはあまり難しくなくて,宣言用のヘッダと実装用のヘッダをそれぞれ用意して,実装用のヘッダをインクルードするだけです。

つまり,Vector<T> の場合,VectorDecl.h みたいなファイルを用意して,次のような宣言を書きます。

template<typename T>
class Vector {
  // Vector<T> の宣言
};

次に,実装ファイルとして Vector.h を書きます。

#include "VectorDecl.h"

template<typename T>
Vector<T>::Vector() { // 実装 }

template<typename T>
Vector<T>::~Vector() { // 実装 }

VectorDecl.h をヘッダ内でインクルードするところがポイント。このクラスを使う場合,Vector.h をインクルードすれば使えるようになります。あまりないだろうけれど,宣言だけを使いたいとき(部分特殊化したりしたソース管理の都合で自前で実装を書きたい場合など)は,VectorDecl.h をインクルードすれば任意に中身を作ることができます。

もっとも,この方法にも欠点があって,ヘッダがふたつになってしまうことから,実装用のヘッダと宣言用のヘッダの管理を工夫する必要が出てきます。特にファイル名が困る。

あたしゃ今のところ,宣言用のヘッダには VectorDecl.h のように -Decl をつけているけれども,ファイルの命名規則にそぐわないところがあって,なかなかうまい管理方法が見つかっていません。実装ファイルの方を Vector.impl とかにして,こいつをインクルードするのもひとつの手だけれど,*.h 以外のファイルをインクルードするのには,ちと抵抗があります。

ま,やり方に一貫性があれば,どのやり方でもいいわけですけれど,なかなか……ね。要は気持ちの問題ともいえなくもなかったりするわけで。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN