0

これらの為替操作国に関する文書はほとんどないようです。私はこれを試行錯誤で理解しようとしています。サンプルプログラムを考えてみましょう。

class CAccountingMoneyPunctFacet : public std::moneypunct<char>
{
protected:
    virtual string_type do_curr_symbol() const      {return ")";}
    virtual char_type do_thousands_sep() const      {return ',';}
    virtual char_type do_decimal_point() const      {return '.';}
    virtual string_type do_positive_sign() const    {return "";}
    virtual string_type do_negative_sign() const    {return "(";}
    virtual string_type do_grouping() const         {return "\03";}
    virtual int do_frac_digits() const              {return 2;}

    virtual pattern do_pos_format() const
    {
        pattern p;
        p.field[0] = value;
        p.field[1] = none;
        p.field[2] = none;
        p.field[3] = none;
        return p;
    }

    virtual pattern do_neg_format() const
    {
        pattern p;
        p.field[0] = sign;
        p.field[1] = value;
        p.field[2] = symbol;    // Very retarded C++ standard need to do this kind of a hack for negative numbers!
        p.field[3] = none;
        return p;
    }
};


int main(int argc,char* argv[])
{
    std::ostringstream oss;
    oss.imbue(std::locale(std::locale(),new CAccountingMoneyPunctFacet));
    oss <<  std::put_money(1234567.23) << std::endl;
//      << (-1234567) << " " << std::setiosflags(std::ios_base::showbase) << std::put_money(-12345678911.314159) << std::endl;
    std::cerr << oss.str();
return 0;
}

このコードの問題は、12,345.67を出力することです。小数点以下が失われただけでなく、100倍ずれているため、これはかなり悪いことです。MSVC++ STLの実装を見ると、かなり困惑していました。

virtual _OutIt __CLR_OR_THIS_CALL do_put(_OutIt _Dest,
    bool _Intl, ios_base& _Iosbase, _Elem _Fill,
        long double _Val) const
    {   // put long double to _Dest
    bool _Negative = false;
    if (_Val < 0)
        _Negative = true, _Val = -_Val;

    size_t _Exp;
    for (_Exp = 0; 1e35 <= _Val && _Exp < 5000; _Exp += 10)
        _Val /= 1e10;   // drop 10 zeros before decimal point

    string_type _Val2;
    char _Buf[40];

    **int _Count = _CSTD sprintf_s(_Buf, sizeof (_Buf), "%.0Lf",**
        _Val);  // convert to chars

    for (int _Off = 0; _Off < _Count; ++_Off)
        _Val2.append((typename string_type::size_type)1,
            _MAKLOCCHR(_Elem, _Buf[_Off], _Cvt));   // convert chars
    _Val2.append(_Exp,
        _MAKLOCCHR(_Elem, '0', _Cvt));  // scale by trailing zeros

    return (_Putmfld(_Dest, _Intl, _Iosbase, _Fill, _Negative, _Val2));
    }

doubleを取るが、すべての小数を切り落とすsprintfを持つ関数を観察します。車輪の再発明をやり直す前に、ここでC++の専門家の意見を聞きたいと思います。

4

1 に答える 1

3

これらはすべて、C++標準の直接的な要件です。

§22.4.6.2.2[locale.money.put.virtuals]/1

ct.widen(buf1, buf1 + sprintf(buf1, "%.0Lf", units), buf2)引数単位は、パターンが。の結果であるかのように、ワイド文字のシーケンスに変換されmp.pos_format()ます。

ここにmpファセットstd::moneypunctがあるので、その要件を続けて、

§22.4.6.3[locale.moneypunct]/3

小数点以下に必要な桁数(存在する場合)は、正確に。によって返される値frac_digits()です。

そして最後に、 §22.4.6.3.2[locale.moneypunct.virtuals] / 6

int do_frac_digits() const;戻り値:小数点以下の基数区切り記号(ある場合)の後の桁数。[261]

261)一般的な米国のロケールでは、これは2です。

これはすべて、実際に「への議論put_moneyはセントである」と要約することができます

于 2012-12-29T07:08:25.703 に答える