最終更新日時:
が更新

履歴 編集

function
<locale>

std::money_put::put

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) : 数字の列として与えられた金額を出力する

intltrueの場合、国際通貨表現(moneypunct<charT, true>)の書式が使用される。

戻り値

基本的な使い方

#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

関連項目