<boost/format.hpp>
format クラスは printf に似た、ユーザ定義型も扱える型安全な書式化処理を提供する。
(このライブラリは他の boost ライブラリに依存しない)
format オブジェクトは書式文字列から構築され、その後 operator% を繰り返し呼び出されることで引数を与えられる。
それぞれの引数は文字列に変換され、書式文字列に従って順に一つの文字列へと結合される。
cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50; // "writing toto, x=40.230 : 50-th try"と表示
のようにするか、あるいは後で、cout << format("%2% %1%") % 36 % 77 )
とすることで、フォーマッタに変数を食わせることができる。format fmter("%2% %1%"); fmter % 36; fmter % 77;
// 先ほど作って引数を与えた fmter の結果を表示: cout << fmter ; // 結果の文字列を取り出せる: string s = fmter.str(); // 何度でも: s = fmter.str( ); // すべてのステップを一度に行うこともできる: cout << boost::format("%2% %1%") % 36 % 77; string s2 = boost::io::str( format("%2% %1%") % 36 % 77 );
using namespace std; using boost::format; using boost::io::group; using boost::io::str;
表示はこうなる : "11 22 333 22 11 \n"cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // '単純な'形式。
表示はこうなる : "(x,y) = ( -23, +35) \n"cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35; // POSIX版Printf形式
表示はこうなる : "writing toto, x=40.23 : 50-th step \n"cout << format("writing %s, x=%s : %d-th step \n") % "toto" % 40.23 % 50;
表示はどれも : "(x,y) = ( -23, +35) \n"cout << format("(x,y) = (%+5d,%+5d) \n") % -23 % 35; cout << format("(x,y) = (%|+5|,%|+5|) \n") % -23 % 35; cout << format("(x,y) = (%1$+5d,%2$+5d) \n") % -23 % 35; cout << format("(x,y) = (%|1$+5|,%|2$+5|) \n") % -23 % 35;
どちらも同じように表示する : "_ +101_ 101 \n"format fmter("_%1$+5d_ %1$d \n"); format fmter2("_%1%_ %1% \n"); fmter2.modify_item(1, group(showpos, setw(5)) ); cout << fmter % 101 ; cout << fmter2 % 101 ;
マニピュレータは、 %1% が現れるたびに適用されるので、出力はこうなる : "_ +101_ +101 \n"cout << format("_%1%_ %1% \n") % group(showpos, setw(5), 101);
names 、 surnames 、そして tel などのベクタ(sample_new_features.cpp を参照)は次のように表示される :for(unsigned int i=0; i < names.size(); ++i) cout << format("%1%, %2%, %|40t|%3%\n") % names[i] % surname[i] % tel[i];
Marc-Françis Michel, Durand, +33 (0) 123 456 789 Jean, de Lattre de Tassigny, +33 (0) 987 654 321
sample_formats.cpp は format の簡単な使い方をデモする。
sample_new_features.cpp は、単純な位置指定命令、中寄せ、そして「桁送り」など、 printf の構文に追加された書式化機能のいくつかを説明する。
sample_advanced.cpp は、 format オブジェクトの
再利用や修飾といった、さらに進んだ機能の使い方をデモする。
そして sample_userType.cpp はユーザ定義型に対する format の振る舞いを示す。
boost::format( format-string ) % arg1 % arg2 % ... % argN
format-string は特殊な命令を含むテキストである。これらの命令は、与えられた引数の書式化結果の文字列によって置換される。
C/C++ の世界におけるレガシーな構文は printf で使われているものである。そのため format は printf の書式文字列をそのまま利用でき、同じ結果を生成する。(ほとんどの場合において。詳細は Incompatibilities with printf を見よ)
この中核となる構文は、新機能を許すだけでなく、 C++ のストリームの文脈に適合するために拡張された。そのため、 format は書式文字列のさまざまな形式の命令を受け付ける :
Boost.format でサポートされる printf の書式指定子は、引数の位置指定をサポートしない標準 C の printf よりも、むしろ Unix98Open-group printf の構文に従っている。
(両者の間では共通のフラグは同じ意味を持つので、誰も頭痛に悩まされることはない)
なお、一つの書式文字列に位置指定付きの書式指定子(例. %3$+d)と位置指定なしのもの(例. %+d)を混ぜて使用するのはエラーである。
Open-group の仕様では同じ引数を複数回参照すること(例. "%1$d %1$d")は未定義動作であるが、 Boost.format では各引数を何度でも参照できる。ただ一つの制約は、書式文字列に現れる最大の引数の数が P であるとき、必ず P 個の引数を期待することである。(例. "%1$d %10$d" ならば P == 10)
引数の数が多すぎても少なすぎても例外が起こる。
(そうでないようにセットされていなければ。 exceptions を参照)
書式指定子 spec は次の形式を持つ :
[ N$ ] [ flags ] [ width ]
[ . precision ] type-char
大括弧で囲われたフィールドは省略可能である。
各フィールドは以下のリストのように説明される :
フラグ 意味 内部ストリームへの作用 '-' 左寄せ N/A (後で文字列に適用される) '=' 中寄せ N/A (後で文字列に適用される)
printf には存在しない(追加機能)'+' 正の数であっても符号を表示する showpos をセットする '#' 基数および小数点を表示する showbase と showpoint をセットする '0' 0 で穴埋めする(符号および基数表示の後に挿入) 左寄せでない場合、 setfill('0') を呼び出し internal をセットする
ユーザ定義型を扱うためにストリーム変換の後に追加の動作を行う' ' 文字列が + または - から始まらない場合、変換された文字の前に space を挿入 N/A (後で文字列に適用される)
printf のものとは挙動が異なる : 内部のアライメントには影響されない- width は変換の結果文字列に対する最小の幅を指定する。 必要ならば、文字列はアライメントにあわせてパディングされ、文字で埋める。この文字はマニピュレータ経由でストリームにセットされたものか、あるいは書式文字列で指定された文字(例. '0', '-', ... などのフラグ)である。
この幅は変換ストリームにセットされるのではないことに注意してほしい。 ユーザ定義型の出力をサポートする(これはいくつかのメンバに operator<< を何度も呼び出すことになりうる)ため、幅の取り扱いはすべての引数オブジェクトのストリーム変換の後に、 format クラスのコードの中で行われる。- precision (小数点の後に続く)はストリームの精度をセットする。
- 浮動少数点型の数値を出力する場合、
- 固定小数点表示モードまたは指数表示モードでは、小数点より後ろの数字の最大文字数を設定する。
- デフォルトモード(%g のような'ジェネラルモード')では、全体の数字の最大文字数を設定する。
- type-char が s または S の場合は別の意味を持つ : 変換文字列は最初の precision 文字で切り詰められる。 (width によるパディングは、この切り詰めの後で施される。)
- type-char 。これは、対象になっている引数が指定した型のいずれかであることを強要しない。その型指定子に関連付けられたフラグをセットするだけである。
型変換指定文字 意味 ストリームへの作用 p または x 16進数で出力 hex をセットする o 8進数で出力 oct をセットする e 浮動小数点数の指数表記 floatfield ビットを scientific にセットする f 浮動小数点数の固定小数点表記 floatfield ビットを fixed にセットする g 一般的な -デフォルトの- 浮動小数点表記 すべての floatfield ビットを外す X, E または G それぞれの小文字と同じように作用。ただし数値の出力に際して大文字を用いる。(指数、16進数、..) 'x', 'e', または 'g' と同じ作用に加え、 uppercase をセットする。 d, i または u 10進数で出力 basefield ビットを dec にセットする s または S 文字列を出力 precision 指定子が外され、値は後の'切り詰め'のために内部フィールドへ送られる。 (上記の precision の説明を参照) c または C 1文字出力 変換文字列の最初の文字のみが用いられる。 % 文字%を表示 N/A 'n' 型指定子は、こうした流れに合わないので、無視される(そして対応する引数も)。
また、 printf の 'l', 'L', あるいは 'h' 修飾子(ワイド、ロングおよびショート型を示す)もサポートされている(が、内部ストリームには何の作用もしない)。
x1, x2 という二つの変数(組み込み型で、 C の printf でサポートされているもの)と書式文字列sがあって、
printf 関数で以下のように使われるとする :
printf(s, x1, x2);
しかしいくつかの printf 書式指定子はストリームの書式化オプションに上手く翻訳されないため、 Boost.format の printf エミュレーションには注意すべき僅かな不完全性がある。cout << format(s) % x1 % x2;
format formatter("%+5d"); cout << formatter % x; unsigned int n = formatter.str().size();
ストリーム状態の修飾に翻訳されたすべてのフラグは、ユーザ定義型にも再帰的に作用する。
( フラグはアクティブなまま残るので、
ユーザ定義クラスによって呼ばれる各々の '<<' 演算に対しても、期待するオプションが渡される)
例.妥当なクラス Rational なら次のようになる :
Rational ratio(16,9); cerr << format("%#x \n") % ratio; // -> "0x10/0x9 \n"
その他の書式化オプションでは話は異なる。例えば、幅の設定はオブジェクトによって生成される最終出力に適用され、内部の各々の出力には適用されない。これは都合のいい話である :
cerr << format("%-8d") % ratio; // -> "16/9 " であって、 "16 /9 " ではない cerr << format("%=8d") % ratio; // -> " 16/9 " であって、 " 16 / 9 " ではない
しかし、 0 や ' ' オプションにも同様に働くため、不自然なことになってしまう。(意地の悪いことに、 '+' が showpos によってストリームの状態へと直接翻訳できるのに対して、 printf のゼロやスペースに当たるオプションはストリームには存在しない) :
cerr << format("%+08d \n") % ratio; // -> "+00016/9" cerr << format("% 08d \n") % ratio; // -> "000 16/9"
format の内部ストリームの状態は、引数を出力する直前に保存され、直後に復帰される。そのため、修飾子の影響は後まで引きづられずに、適用される引数にだけ作用する。
ストリームのデフォルト状態は標準で述べられているように :
精度 6 、幅 0 、右寄せ、そして10進数基数である。
format ストリームの内部ストリームの状態は引数と一緒に渡されるマニピュレータによって変えることができる; group 関数を経由して以下のようにできる :
cout << format("%1% %2% %1%\n") % group(hex, showbase, 40) % 50; // "0x28 50 0x28\n" と表示
cout << format("%1$d %2% %1%\n") % group(hex, showbase, 40) % 50; // "0x28 50 0x28\n" と表示
Boost.format は format オブジェクトの使い方にいくつかのルールを強要する。書式文字列は前述の構文に従わなくてはならず、ユーザは最終的な出力までに正しい個数の引数を供給しなければならない。また modify_item や bind_arg を用いるなら、項目や引数のインデックスが範囲外を指してはならない。
ミスが見過ごされたり放置されたりしないように、 format はいずれかのルールが満たされていないことを検出すると対応する例外を発生する。
しかしユーザはこの振る舞いを必要に応じて変えることができる。また、どのエラーの型が発生するかを次の関数を用いて選択できる :
unsigned char exceptions(unsigned char newexcept); // クエリおよび設定 unsigned char exceptions() const; // クエリのみ
ユーザは、以下のアトムを2進演算で結合することで引数 newexcept を算出できる :
すると、必要とされるよりも多くの引数を与えても許される(単に無視される) :boost::format my_fmt(const std::string & f_string) { using namespace boost::io; format fmter(f_string); fmter.exceptions( all_error_bits ^ ( too_many_args_bit | too_few_args_bit ) ); return fmter; }
また、すべての引数が与えられる前に結果を問い合わせると、結果の対応する部分は単に空になるcout << my_fmt(" %1% %2% \n") % 1 % 2 % 3 % 4 % 5;
cout << my_fmt(" _%2%_ _%1%_ \n") % 1 ; // prints " __ _1_ \n"
namespace boost { template<class charT, class Traits=std::char_traits<charT> > class basic_format { public: typedef std::basic_string<charT, Traits> string_t, basic_format(const charT* str); basic_format(const charT* str, const std::locale & loc); basic_format(const string_t& s); basic_format(const string_t& s, const std::locale & loc); string_t str() const; // pass arguments through those operators : template<class T> basic_format& operator%(T& x); template<class T> basic_format& operator%(const T& x); // dump buffers to ostream : friend std::basic_ostream<charT, Traits>& operator<< <> ( std::basic_ostream<charT, Traits>& , basic_format& ); // ............ これはただの抜粋である ....... }; // basic_format typedef basic_format<char > format; typedef basic_format<wchar_t > wformat; namespace io { // free function for ease of use : template<class charT, class Traits> std::basic_string<charT,Traits> str(const basic_format<charT,Traits>& f) { return f.str(); } } //namespace io } // namespace boost
このクラスのゴールは、より良い、 C++ 用の、型安全かつ型拡張性のある printf の等価物が、 ストリームとともに用いられるようにすることである。
正確には、 format は以下の機能を実現するようデザインされた :デザインの過程で多くの問題に直面し、いくつかの選択をすることになったが、 中には直観的には正しくないものもあった。しかしいずれのケースにも 何らかの意味がある。
Boost format の著者は Samuel Krempp である。 彼は Rüiger Loos と Karl Nelson の両者の format クラスのアイディアを利用した。
February 19, 2002
© Copyright Samuel Krempp 2002. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.
Japanese Translation Copyright © 2003 Kent.N
オリジナルの、及びこの著作権表示が全ての複製の中に現れる限り、この文書の複製、利用、変更、販売そして配布を認める。このドキュメントは「あるがまま」に提供されており、いかなる明示的、暗黙的保証も行わない。また、いかなる目的に対しても、その利用が適していることを関知しない。
このドキュメントの対象: Boost Version 1.29.0
最新版ドキュメント (英語)