「明らかな」解決策は、マニピュレータを使用して、必要に応じて s をstd::num_put<char>
フォーマットするだけのカスタム ファセットをインストールすることです。int
上記のステートメントは、ソリューションを完全に説明していますが、少しわかりにくいかもしれません。以下は、実際にロジックを実装するためのコードです。最初の要素は、関数の 1 つから派生し、それをオーバーライドするクラスである特別なstd::num_put<char>
ファセットです。used ファセットは、( を使用して) ストリームに格納されたフラグを調べて、動作を変更する必要があるかどうかを判断するフィルタリング ファセットです。コードは次のとおりです。std::num_put<char>
virtual
iword()
class num_put
: public std::num_put<char>
{
std::locale loc_;
static int index() {
static int rc(std::ios_base::xalloc());
return rc;
}
friend std::ostream& twodigits(std::ostream&);
friend std::ostream& notwodigits(std::ostream&);
public:
num_put(std::locale loc): loc_(loc) {}
iter_type do_put(iter_type to, std::ios_base& fmt,
char fill, long value) const {
if (fmt.iword(index())) {
fmt.width(2);
return std::use_facet<std::num_put<char> >(this->loc_)
.put(to, fmt, '0', value);
}
else {
return std::use_facet<std::num_put<char> >(this->loc_)
.put(to, fmt, fill, value);
}
}
};
主要部分はdo_put()
、値をどのようにフォーマットする必要があるかを決定するメンバー関数です。フラグ infmt.iword(index())
がゼロ以外の場合、幅を に2
設定し、塗りつぶし文字でフォーマット関数を呼び出します0
。とにかく幅はリセットされ、塗りつぶし文字はストリームに保存されません。つまり、クリーンアップの必要はありません。
通常、コードはおそらく別の翻訳単位に存在し、ヘッダーで宣言されません。ヘッダーで実際に宣言される唯一の関数は、メンバー関数へのアクセスを提供するためにこの場合 s にされるtwodigits()
andです。メンバー関数は、呼び出されたときに使用できるインデックスを割り当てるだけで、このインデックスを返すだけです。マニピュレータは、主にこのインデックスを設定します。ストリームにファセットがインストールされていない場合は、ファセットもインストールされます。notwodigits()
friend
index()
index()
std::ios_base::iword()
twodigits()
notwodigits()
num_put
twodigits()
std::ostream& twodigits(std::ostream& out)
{
if (!dynamic_cast<num_put const*>(
&std::use_facet<std::num_put<char> >(out.getloc()))) {
out.imbue(std::locale(out.getloc(), new num_put(out.getloc())));
}
out.iword(num_put::index()) = true;
return out;
}
std::ostream& notwodigits(std::ostream& out)
{
out.iword(num_put::index()) = false;
return out;
}
twodigits()
マニピュレータは、 を使用してファセットnum_put
を割り当てnew num_put(out.getloc())
ます。std::locale
オブジェクトにファセットをインストールすると必要なクリーンアップが行われるため、クリーンアップは必要ありません。std::locale
ストリームのオリジナルには、 を使用してアクセスしout.getloc()
ます。ファセットによって変更されます。理論的には、フラグを使用する代わりにnotwodigits
オリジナルを復元できます。std::locale
ただし、imbue()
比較的高価な操作になる可能性があり、フラグを使用する方がはるかに安価です。もちろん、似たような整形フラグがたくさんあると、違ってくるかもしれませんが…。
マニピュレータの使用方法を示すために、以下に簡単なテスト プログラムを示します。ファセットが 1 回だけ作成されることを確認するために、書式設定フラグをtwodigits
2 回設定します (std::locale
書式設定を通過する s のチェーンを作成するのは少しばかげています。
int main()
{
std::cout << "some-int='" << 1 << "' "
<< twodigits << '\n'
<< "two-digits1='" << 1 << "' "
<< "two-digits2='" << 2 << "' "
<< "two-digits3='" << 3 << "' "
<< notwodigits << '\n'
<< "some-int='" << 1 << "' "
<< twodigits << '\n'
<< "two-digits4='" << 4 << "' "
<< '\n';
}