これは可能ですが、やや自明ではなく、それを行う正しい方法はかなりあいまいです。
余談ですが、オペランドの1つmsg << myval;
だけがユーザー定義型でなければならないようなことをするときは、ここに当てはまります(定義していなくても、公式にはユーザーです-定義されたタイプ)。それは多かれ少なかれ関係ありません。の既存のオーバーロードは正常に機能します。独自のものを提供する必要はありません。ostringstream
operator<<
私はストリームを「仲人」と考えています。実際の 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;
}
ただし、これは非常に迅速にまとめられ、テストは最小限に抑えられていることを付け加えておきます。これはテストケースで機能し、おそらく他の狭いストリームでも機能します。推測では、幅の広いストリームで正しく動作するには、おそらくさらに多くの作業が必要です。