質問

私は、クラス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::endlstd::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、で傍受することができます。あなたが傍受し、彼らがoverflowedまたは手動でsyncedされているように、すべての改行文字を変更して文字列に変換する必要があります。

オーバーライドバッファクラスを設計basic_streambufは、そのバッファメモリへの直接アクセスを期待するので面倒です。これは、簡単に既存のbasic_streambufにI / O要求を渡すのを防ぐことができます。あなたは手足に外出する必要があり、ストリームバッファクラスを知っていると仮定し、そこから派生します。 (cincoutは、私が言うことができるまでのところとして、basic_filebufを使用することを保証するものではありません。)その後、ちょうどvirtual overflowsyncを追加します。置換を行うことは前もってそれを割り当てるので注意してください追加のスペースを必要とするかもしれない(§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のアドレスを確認することができます。私はそれが役に立てば幸います。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top