iter_type
put(iter_type s,
bool intl,
ios_base& f,
char_type fill,
long double quant) const; // (1) C++98
iter_type
put(iter_type s,
bool intl,
ios_base& f,
char_type fill,
const string_type& quant) const; // (2) C++98
概要
金額を書式化して、出力イテレータsへ出力する。
- (1) : 整数値として与えられた金額を出力する
- (2) : 数字の列として与えられた金額を出力する
intlがtrueの場合、国際通貨表現(moneypunct<charT, true>)の書式が使用される。
戻り値
- (1), (2) :
do_put(s, intl, f, fill, quant)の戻り値
例
基本的な使い方
#include <iostream>
#include <sstream>
#include <locale>
#include <iterator>
int main()
{
std::ostringstream oss;
const auto& facet = std::use_facet<std::money_put<char>>(oss.getloc());
facet.put(std::ostreambuf_iterator<char>{oss}, false, oss, ' ', 105623.0L);
std::cout << oss.str() << std::endl;
}
出力例
105623
"C"ロケールでは通貨記号も桁区切りも設定されていないため、数字のみが出力される
通貨記号と桁区切りを指定する
書式はstd::moneypunctファセットから取得される。"C"ロケールでは通貨記号も桁区切りも設定されていないため、これらを持つファセットをロケールへ組み込む。
#include <iostream>
#include <sstream>
#include <locale>
#include <iterator>
#include <string>
// 通貨記号と桁区切りを持つmoneypunctファセット
struct my_moneypunct : std::moneypunct<char> {
protected:
char_type do_decimal_point() const override { return '.'; }
char_type do_thousands_sep() const override { return ','; }
std::string do_grouping() const override { return "\3"; } // 3桁ごとに区切る
string_type do_curr_symbol() const override { return "$"; }
string_type do_negative_sign() const override { return "-"; }
int do_frac_digits() const override { return 2; } // 小数点以下2桁
pattern do_pos_format() const override { return pattern{{symbol, sign, none, value}}; }
pattern do_neg_format() const override { return pattern{{symbol, sign, none, value}}; }
};
int main()
{
std::ostringstream oss;
oss.imbue(std::locale{std::locale::classic(), new my_moneypunct{}});
const auto& facet = std::use_facet<std::money_put<char>>(oss.getloc());
// showbaseを設定すると通貨記号が出力される
oss.setf(std::ios_base::showbase);
facet.put(std::ostreambuf_iterator<char>{oss}, false, oss, ' ', 105623.0L);
oss << '\n';
// showbaseを設定しない場合、通貨記号は出力されない
oss.unsetf(std::ios_base::showbase);
facet.put(std::ostreambuf_iterator<char>{oss}, false, oss, ' ', 105623.0L);
oss << '\n';
// 負の値にはdo_neg_format()のパターンが使用される
oss.setf(std::ios_base::showbase);
facet.put(std::ostreambuf_iterator<char>{oss}, false, oss, ' ', -105623.0L);
std::cout << oss.str() << std::endl;
}
出力
$1,056.23
1,056.23
$-1,056.23
- 引数の
105623は最小単位(この例ではセント)での金額であり、do_frac_digits()が2であるため1,056.23と表示される
通貨記号を末尾に置く(日本円の例)
通貨記号の位置はdo_pos_format()・do_neg_format()が返すパターンで決まる。valueより後ろにsymbolを置くことで、「1,000円」のように値の後ろへ通貨記号を出力できる。
#include <iostream>
#include <sstream>
#include <locale>
#include <iterator>
#include <string>
// 日本円のmoneypunctファセット
struct jpy_moneypunct : std::moneypunct<char> {
protected:
char_type do_thousands_sep() const override { return ','; }
std::string do_grouping() const override { return "\3"; }
string_type do_curr_symbol() const override { return "円"; }
string_type do_negative_sign() const override { return "-"; }
int do_frac_digits() const override { return 0; } // 円に補助単位はない
// 値の後ろに通貨記号を置く
pattern do_pos_format() const override { return pattern{{sign, value, none, symbol}}; }
pattern do_neg_format() const override { return pattern{{sign, value, none, symbol}}; }
};
int main()
{
std::ostringstream oss;
oss.imbue(std::locale{std::locale::classic(), new jpy_moneypunct{}});
oss.setf(std::ios_base::showbase);
const auto& facet = std::use_facet<std::money_put<char>>(oss.getloc());
facet.put(std::ostreambuf_iterator<char>{oss}, false, oss, ' ', 105623.0L);
oss << '\n';
facet.put(std::ostreambuf_iterator<char>{oss}, false, oss, ' ', -105623.0L);
std::cout << oss.str() << std::endl;
}
出力
105,623円
-105,623円
do_frac_digits()が0であるため、引数の値がそのまま円単位の金額として扱われる
ロケールによって通貨を切り替える
金額の書式は、put()へ渡すストリームのロケールに設定されたstd::moneypunctファセットから取得される。そのため、名前付きロケールを指定するだけで、同じ値を各国の通貨の書式で出力できる。
#include <iostream>
#include <sstream>
#include <locale>
#include <iterator>
#include <string>
#include <stdexcept>
// 書式化の処理自体はロケールに依存しない
std::string format_money(const std::locale& loc, long double units)
{
std::ostringstream oss;
oss.imbue(loc);
oss.setf(std::ios_base::showbase);
const auto& facet = std::use_facet<std::money_put<char>>(oss.getloc());
facet.put(std::ostreambuf_iterator<char>{oss}, false, oss, ' ', units);
return oss.str();
}
int main()
{
for (const char* name : {"en_US.UTF-8", "ja_JP.UTF-8", "de_DE.UTF-8"}) {
try {
// 同じ値を、ロケールごとの通貨の書式で出力する
std::string s = format_money(std::locale{name}, 105623.0L);
std::cout << name << " : " << s << std::endl;
}
catch (const std::runtime_error&) {
// 指定した名前のロケールが利用できない場合
std::cout << name << " : not available" << std::endl;
}
}
}
出力例
en_US.UTF-8 : $1,056.23
ja_JP.UTF-8 : ¥105,623
de_DE.UTF-8 : 1.056,23 €
- 米ドルとユーロは補助単位を持つため小数点以下2桁で表示され、日本円は
frac_digits()が0であるため105623がそのまま円単位の金額として表示される - ドイツのロケールでは桁区切りと小数点が米国と逆であり、通貨記号は値の後ろに置かれる
- 妥当なロケール名は処理系定義である。指定した名前のロケールが利用できない場合、
std::localeのコンストラクタはstd::runtime_errorを送出し、上記の例ではnot availableが出力される
バージョン
言語
- C++98