std :: ENDLの過負荷処理?
-
19-09-2019 - |
質問
私は、クラスMyStream
を定義したいようにます:
MyStream myStream;
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
タグの出力が得られます
[blah]123
[blah]56
[blah]78
基本的に、私が欲しい "[何とか]" すべてのの無終端のstd::endl
後に挿入し、その後、先頭に挿入?
ここでの難しさは、ロジック管理ではなく、std::endl
の取り扱いを検出し、過負荷します。これを行うには、エレガントな方法はありますか?
ありがとうございます。
編集:私はロジック管理上の助言を必要としません。私は/ std::endl
の過負荷印刷を検出する方法を知っておく必要があります。
解決
あなたがする必要がどのような独自のストリームバッファを書き込みます:
ストリームバッファは、あなたの出力をフラッシュされるときには、文字やストリームの内容を接頭辞ます。
次のような作品をSTD :: ENDLは、次の原因となるからです。
1)ストリームに '\ n' を追加します。
2)ストリーム上)(flushを呼び出し
図2(a))これは、ストリームバッファにpubsync()を呼び出します。
図2b)これは、仮想メソッドの同期()を呼び出し
図2c)あなたがしたい仕事をするために、この仮想メソッドをオーバーライドします。
#include <iostream>
#include <sstream>
class MyStream: public std::ostream
{
// Write a stream buffer that prefixes each line with Plop
class MyStreamBuf: public std::stringbuf
{
std::ostream& output;
public:
MyStreamBuf(std::ostream& str)
:output(str)
{}
~MyStreamBuf() {
if (pbase() != pptr()) {
putOutput();
}
}
// When we sync the stream with the output.
// 1) Output Plop then the buffer
// 2) Reset the buffer
// 3) flush the actual output stream we are using.
virtual int sync() {
putOutput();
return 0;
}
void putOutput() {
// Called by destructor.
// destructor can not call virtual methods.
output << "[blah]" << str();
str("");
output.flush();
}
};
// My Stream just uses a version of my special buffer
MyStreamBuf buffer;
public:
MyStream(std::ostream& str)
:std::ostream(&buffer)
,buffer(str)
{
}
};
int main()
{
MyStream myStream(std::cout);
myStream << 1 << 2 << 3 << std::endl << 5 << 6 << std::endl << 7 << 8 << std::endl;
}
> ./a.out
[blah]123
[blah]56
[blah]78
>
他のヒント
MyStream
クラスのあなたのオーバーロードされた事業者は、前の印刷・トークンだった-ENDLフラグを設定する必要があります。
次のオブジェクトを印刷する場合は、次に、[blah]
はそれの前に挿入することができる。
std::endl
はstd::ostream
への参照を取得し、返す関数です。それはあなたのストリームにシフトして検出するために、あなたはあなたのタイプと、そのような機能の間operator<<
をオーバーロードする必要があります:
MyStream& operator<<( std::ostream&(*f)(std::ostream&) )
{
std::cout << f;
if( f == std::endl )
{
_lastTokenWasEndl = true;
}
return *this;
}
原理にニールと合意しています。
あなたはそれが入出力ストリームを拡張する唯一の方法であるため、バッファの動作を変更したいです。 endl
はこれを行います:
flush(__os.put(__os.widen('\n')));
widen
は、単一の文字を返しますので、あなたはそこにあなたの文字列を入れることはできません。 put
は仮想関数ではなく、たまにしかputc
にフックoverflow
を呼び出します。あなたは、バッファのflush
を呼び出しsync
、で傍受することができます。あなたが傍受し、彼らがoverflow
edまたは手動でsync
edされているように、すべての改行文字を変更して文字列に変換する必要があります。
オーバーライドバッファクラスを設計basic_streambuf
は、そのバッファメモリへの直接アクセスを期待するので面倒です。これは、簡単に既存のbasic_streambuf
にI / O要求を渡すのを防ぐことができます。あなたは手足に外出する必要があり、ストリームバッファクラスを知っていると仮定し、そこから派生します。 (cin
とcout
は、私が言うことができるまでのところとして、basic_filebuf
を使用することを保証するものではありません。)その後、ちょうどvirtual overflow
とsync
を追加します。置換を行うことは前もってそれを割り当てるので注意してください追加のスペースを必要とするかもしれない(§27.5.2.4.5/ 3および27.5.2.4.2 / 7を参照)。
- または -
ちょうどあなた自身の名前空間、またはより良い、全くendl
と呼ばれていないマニピュレータの新しいendl
を宣言!
の代わりにstd::endl
の動作を変更しようとするのは、おそらく仕事をするためのフィルタリングたstreambufを作成する必要があります。ジェームズ・観世は、それぞれの先頭にタイムスタンプを挿入する方法を示すこの例があります出力ライン。それはあなたがそれぞれの行に好きな接頭辞にそれを変更するためにわずかな変更を必要とする必要があります。
私は、関数ポインタを使用します。これは、Cに使用されていない人々に恐ろしい聞こえるが、それはほとんどの場合、多くの方が効率的です。ここでは例があります:
#include <iostream>
class Foo
{
public:
Foo& operator<<(const char* str) { std::cout << str; return *this; }
// If your compiler allows it, you can omit the "fun" from *fun below. It'll make it an anonymous parameter, though...
Foo& operator<<(std::ostream& (*fun)(std::ostream&)) { std::cout << std::endl; }
} foo;
int main(int argc,char **argv)
{
foo << "This is a test!" << std::endl;
return 0;
}
あなたが本当にしたい場合は、他のいくつかの空/無効機能を取得されていませんが、私は、それはほとんどの場合、それだけの価値はないと思うことを確認するENDLのアドレスを確認することができます。私はそれが役に立てば幸います。
あなたはstd::endl
を変更することはできません - それはだとして名前が、それはC ++標準ライブラリの一部であり、その動作が固定されている示唆しています。あなたはそれが行の終わりを受信したときに、ストリーム自体の動作を変更する必要があります。個人的に、私は努力この価値を考えていないだろうが、あなたがこの地域に進出したい場合、私は強くブック<のhref =「http://www.angelikalanger.com/iostreams.html」を読んでお勧めのrel = "nofollowをnoreferrer ">標準C ++入出力ストリーム&ロケールするます。