## 11.4 抽出子と挿入子の応用

日付の書式は、地域や文化の規約によって異なります。したがって、抽出子と挿入子についての日付の構文解析や書式設定は、通常、そのような規約に基づいて行います。抽出子と挿入子にそれらの機能を追加するには、次の例のように、個々のストリームのロケールに組み込んだ時間ファセットを使用します。

>     template<class charT, class Traits>
>     basic_istream<charT, Traits>&
>     operator >> (basic_istream<charT, Traits >& is, date& dat)
>     {
>      ios_base::iostate err = 0;

>      use_facet<time_get<charT,Traits> >(is.getloc())              //1
>        .get_date(is, istreambuf_iterator<charT,Traits>()          //2
>                 ,is, err, &dat.tm_date);                          //3

>      return is;
>     }

//1 | 入力ストリームのロケールの `time_get` ファセットによって、ロケールで定義した文化的規約に基づいて日付の構文解析を処理します。問題のロケールは、ストリームの `getloc()` 関数で呼び出します。`time_get` ファセットは、`use_facet<..>()` 大域関数に対する呼び出しでアクセスします。`use_facet` 関数テンプレートの型引数は、ファセット型です (ロケールとファセットの詳細については、国際化の章を参照してください)。
//2 | ファセットのメンバー関数 `get_date()` を呼び出します。この関数は、次のように多くの引数をとります。 入力反復子の範囲。パフォーマンスと効率性の理由から、ファセットはストリームのバッファで直接操作します。ファセットは、ストリームのバッファ反復子でストリームバッファにアクセスします (『標準 C++ ライブラリ・ユーザーズガイド』のストリームバッファ反復子の節を参照)。標準 C++ ライブラリのストリームバッファ反復子の規約にもとづいて、反復子の範囲を設定します。範囲はアクセスする最初の文字を示す反復子から、アクセスする最後の文字の後の文字までです (終了位置の後)。 入力シーケンスでは、まずストリームを参照します。`istreambuf_iterator` クラスにはコンストラクタがあり、ここで入力ストリームを参照します。そのため、ストリームに対する参照は、ストリーム内の現在の位置を示す `istreambuf_iterator` に自動的に変換されます。入力シーケンスの最後に、ストリームの最後の反復子が読み込まれます。これは、クラス `istreambuf_iterator` のデフォルトのコンストラクタによって作成されます。以上 2 つのストリームバッファ反復子では、入力ストリームの現在の位置から、日付や無効な文字が見つかるか、入力ストリームの最後に達するまで、入力の構文解析が行われます。
//3 | 他のパラメータは、次のとおりです。 書式設定フラグ。ストリームの `ios_base` 部までの参照をここで指定します。これは、ストリームのメンバー `flags()`、`precision()`、`width()` に対して、ファセットでストリームの書式設定情報を適用するためです。 入出力ストリームの状態。日付の構文解析時のエラー報告に使用します。 時間オブジェクトに対するポインタ。`tm` 型のオブジェクトに対するポインタです。C ライブラリで定義した時間構造です。日付クラスでは、このような時間構造によって個々のデータメンバー `tm_date` にポインタを渡します。

挿入子も同様に構築します。

>     template<class charT, class Traits>
>     basic_ostream<charT, Traits>& operator <<
>      (basic_ostream<charT, Traits >& os, const date& dat)
>     {
>        use_facet
>        <time_put<charT,ostreambuf_iterator<charT,Traits> > >      //1
>        (os.getloc())
>        .put(os,os,os.fill(),&dat.tm_date,'x');                    //2
>        return os;
>     }

//1 | ストリームのロケールの `time_put` ファセットを使用して、日付の書式設定を処理します。
//2 | ファセットの `put()` 関数の引数は、次のとおりです。 出力反復子。`ostreambuf_iterator` に対する出力ストリームへの参照から、自動変換を使用します。出力は、現在の書き込み位置から出力ストリームに挿入されます。 書式設定フラグ。ストリームの `ios_base` 部に参照を与えます。これは、ストリームの書式設定情報を検索するときにファセットで使用します。 空白詰め文字。ストリームの空白詰め文字を使用します。他の空白詰め文字を使用することもできますが、通常はストリームの設定を使用します。 時間構造に対するポインタ。構文解析の結果がこの構造に保存されます。 書式指示子。例にもある `'x'` のような文字です。`%`"%A, %B %d, %Y")。C ライブラリの `strftime()` 関数の書式指示子と同じはたらきがあります。出力される日付は、`Tuesday, June 11, 1996` のようになります。ここでは、書式指示子は使用せず、ロケールの適切な日付表現を指定する簡単な文字として `'x'` を使用します。

以上の挿入子と抽出子が、先の簡単な例と比較してどれだけ違うかを確認してください。以後は、`operator<<(int)` で `date` オブジェクトのデータメンバーを個別に挿入したときのように、組み込み型の既存の挿入子や抽出子だけに頼る必要はありません。代わりに、`time` ファセットの `get_date()` サービスのような、低レベルサービスを使用します。書式制御やエラー処理など、これまで使用してきた挿入子や抽出子のような高レベルのサービスの機能は必要ありません。

ストリームのバッファに直接アクセスすることで、プログラムの実行時の効率面でおそらく同じ成果が得られます。ストリームのバッファのサービスも、書式制御やエラー処理などのタスクを自分で運用することができる低レベルサービスです。

以下の節では、ロケールやストリームバッファなどの低レベル構成要素を直接的に使用して、挿入子と抽出子を改良して完成する方法を説明します。

Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。

OEM リリース, 1998 年 6 月