2006-03-10-01-テンプレートと文字列リテラル
>> Site top >> weblog >> 月別アーカイブ >> 2006年03月のlog >> 2006-03-10-01-テンプレートと文字列リテラル
最終更新日付:2006/03/10 01:00:00
テンプレートと文字列リテラル
2006 年 03 月 10 日
忙しくて気の利いたことを書けない。申し訳ないが開発寄りの話。
c++ では、ワイド文字は wchar_t で扱うことになっている。char と wchar_t は、(通常は)まったく別の型だ。一般に wchar_t は 16 ビット値だし、それぞれの文字列を扱うためのライブラリ関数も別だ。ここでは、1つのプログラムソースで char と wchar_t の2つをテンプレートレベルでサポートしたい場合のことを書く。
ここで、文字型でパラメタライズされたクラステンプレート Foo があるとする。そのメソッド Bar() の中で文字列リテラルを使用したい場合、どうするか。たとえば以下のような感じだと、Foo<char> なら問題ないが、Foo<wchar_t> ではコンパイラが文句を言う。なぜなら、ワイド文字の文字列リテラルでは、手前に L を付けなければならないからだ。
template <typename CT> class Foo { public: typedef CT CharType; public: void Bar( ) { const CharType* p = "Foo::Bar( ) has invoked."; }; };
一般的に、文字環境の切り替えで文字列リテラルを上手に扱うために使用されるのはTEXT("string") といったマクロだ。これは、ワイド文字環境なら L"string" に、そうでなければ "string" に展開される...のだが、実はこれが嫌いなのだ。マクロはコンパイラが関知しないため、ハマると実に不愉快な時間を過ごすことになる。それに、そもそもテンプレートのレベルで文字環境を認識したいのにマクロ定義と同期をとらなければならない。そんなのは変だ。
陰郎がとっている方法は、リテラルを管理するクラステンプレートを作成する方法だ。本体は空にしておき、char および wchar_t で特殊化する...以下のように。インデックスを指定して複数の文字列リテラルを取得できればよいが、 operator( ) を使用しているのは陰郎の趣味だ。
template <typename CT> class Literals { }; template <> class Literals<char> { public: inline const char* operator( )( int idx ) { // ... }; }; template <> class Literals<wchar_t> { public: inline const wchar_t* operator( )( int idx ) { // ... }; };
こうしておけば、以下のようにすることで CharType の実際の型が char でも wchar_tでも動作するようになる。インライン関数にしてあるし、賢いコンパイラならきっちり最適化してインデックス指定のコストを事実上なしにしてくれるだろう。
typedef Literals<CharType> LiteralsT; LiteralsT literals; const CharType* p = literals( 0 );
正直、ここまでやるのはやりすぎかもしれない。しかし、可能な限りプリプロセッサディレクティブを追放することを考えるとこんなふうになってしまった。当然、文字列処理をするライブラリ関数をマクロを使用して使い分けたりもしない。文字型をテンプレートとするクラスユーティリティを作成して切り分けるのだ。ここまでくると立派なものである。ただし、テンプレートを使っているせいでソースコードのほとんどがヘッダファイルに入ることになるが...(汗
コメント
このページのタグ
Page tag : 開発
Copyright(C) 2005-2021 project-enigma.
Generated by CL-PREFAB.