2

Visual C++ で、値が inf の double があり、ストリームを使用して出力した場合:

double myval = std::numeric_limits<double>::infinity();
std::ostringstream msg;
msg << "This is infinite: " << myval;

結果は「1.#INF」です。

単純に「inf」または「INF」と出力する簡単な方法はありますか? この文字列は、後で解析されるテキストに表示され、余分な文字が問題を引き起こしています。

doubleのストリーム演算子をオーバーロードしようと思ったのですが、doubleは組み込み型です。

基本的な質問に対する答えを検索する方法を正確に理解できないことを告白します...

ありがとう!

4

1 に答える 1

1

これは可能ですが、やや自明ではなく、それを行う正しい方法はかなりあいまいです。

余談ですが、オペランドの1つmsg << myval;だけがユーザー定義型でなければならないようなことをするときは、ここに当てはまります(定義していなくても、公式にはユーザーです-定義されたタイプ)。それは多かれ少なかれ関係ありません。の既存のオーバーロードは正常に機能します。独自のものを提供する必要はありません。ostringstreamoperator<<

私はストリームを「仲人」と考えています。実際の I/O を処理するストリーム バッファと、フォーマットを処理するロケールがあります。そのように考えると、解決策はかなり明確になります。変更したいのはフォーマットであり、フォーマットはロケールによって処理されるため、ロケールを変更する必要があります。

ただし、ロケールは実際には異種のコレクションです。具体的には、facetクラスのコレクションです。この場合、気になるのはnum_putファセットです。num_put ファセット クラスにはdo_put、さまざまな型の仮想メンバー関数があります。この場合、私たちが気にするのは次のdoubleとおりです。

template <class charT, class OutputIterator = std::ostreambuf_iterator<charT> >
class num_put : public std::num_put<charT, OutputIterator> {
public:
    virtual iter_type do_put(iter_type i, 
                             std::ios_base& b, 
                             char_type fill, 
                             double v) const 
    {
        if (v == std::numeric_limits<double>().infinity()) {
            static const char inf[]="inf";      
            std::copy(std::begin(inf), std::end(inf), i);
        }
        else {
            std::ostringstream temp;
            temp << v;
            std::copy(temp.str().begin(), temp.str().end(), i);
        }
        return i;           
    }
};

これを使用するには、問題のストリームにそのファセットを含むロケールを吹き込みます。

int main() {
    char *d="0";

    std::locale loc(std::locale::classic(), new num_put<char>);
    std::cout.imbue(loc);

    std::cout << 1.0/atoi(d);
    return 0;
}

ただし、これは非常に迅速にまとめられ、テストは最小限に抑えられていることを付け加えておきます。これはテストケースで機能し、おそらく他の狭いストリームでも機能します。推測では、幅の広いストリームで正しく動作するには、おそらくさらに多くの作業が必要です。

于 2012-09-29T23:44:49.257 に答える