4

stringstreamカスタムを使用してコンソールからの出力をGUIのテキストフィールドにリダイレクトする単純なGUIプログラムがあります(状況によっては)。現在。Enter キーを押すたびにウィンドウが再描画されますが、それ以外のときに出力が生成される可能性があります。ストリームで演算子が使用stringstreamされるたびに実行される関数を登録する方法はありますか?<<

ノート

私のソリューションでは C++11 を使用できないことを指摘しておくべきでした。これをコンパイルして実行するマシンでは、c++11 が利用できません。

4

3 に答える 3

8

個人的には、これにはstd::ostringstream(またはstd::stringstream)をまったく使用しません!代わりに、GUIへのデータ送信を処理する独自のストリームバッファーを作成します。つまり、現在のデータを上書きstd::streambuf::overflow()std::streambuf::sync()てGUIに送信します。また、出力がすぐに送信されるようにするために、を設定しましstd::ostreamstd::ios_base::unitbuf。実際、関数に変更を送信するのは非常に簡単です。つまり、これを実装します。

#include <streambuf>
#include <ostream>
#include <functional>
#include <string>
#include <memory>
#include <iostream> // only for testing...

#if HAS_FUNCTION
typedef std::function<void(std::string)> function_type;
#else
class function_type
{
private:
    struct base {
        virtual ~base() {}
        virtual base* clone() const = 0;
        virtual void  call(std::string const&) = 0;
    };
    template <typename Function>
    struct concrete
        : base {
        Function d_function;
        concrete(Function function)
            : d_function(function) {
        }
        base* clone() const { return new concrete<Function>(this->d_function); }
        void  call(std::string const& value) { this->d_function(value); }
    };
    std::auto_ptr<base> d_function;
public:
    template <typename Function>
    function_type(Function function)
        : d_function(new concrete<Function>(function)) {
    }
    function_type(function_type const& other)
        : d_function(other.d_function->clone()) {
    }
    function_type& operator= (function_type other) {
        this->swap(other);
        return *this;
    }
    ~function_type() {}
    void swap(function_type& other) {
        std::swap(this->d_function, other.d_function);
    }
    void operator()(std::string const& value) {
        this->d_function->call(value);
    }
};
#endif

class functionbuf
    : public std::streambuf {
private:
    typedef std::streambuf::traits_type traits_type;
    function_type d_function;
    char          d_buffer[1024];
    int overflow(int c) {
        if (!traits_type::eq_int_type(c, traits_type::eof())) {
            *this->pptr() = traits_type::to_char_type(c);
            this->pbump(1);
        }
        return this->sync()? traits_type::not_eof(c): traits_type::eof();
    }
    int sync() {
        if (this->pbase() != this->pptr()) {
            this->d_function(std::string(this->pbase(), this->pptr()));
            this->setp(this->pbase(), this->epptr());
        }
        return 0;
    }
public:
    functionbuf(function_type const& function)
        : d_function(function) {
        this->setp(this->d_buffer, this->d_buffer + sizeof(this->d_buffer) - 1);
    }
};

class ofunctionstream
    : private virtual functionbuf
    , public std::ostream {
public:
    ofunctionstream(function_type const& function)
        : functionbuf(function)
        , std::ostream(static_cast<std::streambuf*>(this)) {
        this->flags(std::ios_base::unitbuf);
    }
};

void some_function(std::string const& value) {
    std::cout << "some_function(" << value << ")\n";
}

int main() {
    ofunctionstream out(&some_function);
    out << "hello" << ',' << " world: " << 42 << "\n";
    out << std::nounitbuf << "not" << " as " << "many" << " calls\n" << std::flush;
}

上記のコードのかなりの部分は、実際には目前のタスクとは無関係ですstd::function<void(std::string)>。C++ 2011を使用できない場合に備えて、のプリミティブバージョンを実装しています。

あまり多くの呼び出しが必要ない場合は、オフstd::ios_base::unitbufにして、ストリームをフラッシュするときにのみデータを送信できます。たとえば、を使用しstd::flushます(はい、知ってstd::endlいますが、残念ながら、通常は誤用されているため、データを削除して使用することを強くお勧めしますstd::flushフラッシュが実際に意味されるところ)。

于 2012-10-10T19:48:14.870 に答える
4

これを行うには、独自の streambuf クラスを作成する必要があります。streambuf クラスは IO デバイスを表し、それぞれがその種類のデバイスに固有のさまざまな問題を処理します。標準では、ファイル用の streambuf と文字列用の streambuf が定義されています。ネットワーク アクセスには別のデバイスが使用されます。また、ストリームを使用する場合は、GUI への出力も別の種類のデバイスとして表す必要があります。

適切な streambuf クラスを作成することは簡単ではなく、ややわかりにくいように見えますが、そこにはリソースがあります。C++ 標準ライブラリ - チュートリアルとリファレンスには、これに関する小さなセクションがあります。Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Referenceは、詳細な情報を提供します。を検索するsubclassing basic_streambufと、オンラインで無料のリソースがいくつか見つかります。

于 2012-10-10T19:40:00.303 に答える
1

まだ行っていない場合は、stringstreamからサブクラスを派生させ、そのストリーム挿入演算子をオーバーロードしてイベントを生成できますか?

擬似コード:

class AlertingStream : public stringstream
{
    ostream& operator << (type)
    {
        for (each listener in listeners)
        {
            listener.notify();
        }
        perform insertion;
        return *this;
    }
}
于 2012-10-10T19:29:09.853 に答える