4

ストリームのオーバーロードによってc++内で同時にファイルとstdoutに書き込もうとしています

test.h

 #pragma once 

#include <iostream>

using  std::ofstream;

class OutputAndConsole:public ofstream
{
public:
    std::string fileName;        
    OutputAndConsole(const std::string& fileName):ofstream(fileName),fileName(fileName){
    };
    template <typename T>
    OutputAndConsole& operator<<(T var);
};


template <typename T>
OutputAndConsole& OutputAndConsole::operator<<(T var)
{
    std::cout << var;
    ofstream::operator << (var);
    return (*this);
};

test.cpp

  OutputAndConsole file("output.txt");
  file << "test" ;

ファイルの出力は次のとおりです。

01400930

しかし、コンソールには

test

入力しているように見えるコードをデバッグしました

_Myt& __CLR_OR_THIS_CALL operator<<(const void *_Val)

私は何が間違っているのですか?

4

2 に答える 2

8

正しく機能するようにパッチを適用できないことが主な理由で、あなたのアプローチが機能しない理由についてはコメントしません。std::ostream&主な問題は、ストリームを使用して、それを期待するものに渡し、それでも両方のストリームに書き込むことができないことです。ただし、実際に必要なものを実装するには、必ずしも明白ではありませんが、比較的単純なアプローチがあります。新しいストリームバッファ、つまり、から派生したクラスを派生させ、その関数と関数std::streambufをオーバーライドします。簡単なデモの完全なコードは次のとおりです。overflow()sync()

#include <streambuf>

struct teebuf
    : std::streambuf
{
    std::streambuf* sb1_;
    std::streambuf* sb2_;

    teebuf(std::streambuf* sb1, std::streambuf* sb2)
        : sb1_(sb1), sb2_(sb2) {
    }
    int overflow(int c) {
        typedef std::streambuf::traits_type traits;
        bool rc(true);
        if (!traits::eq_int_type(traits::eof(), c)) {
            traits::eq_int_type(this->sb1_->sputc(c), traits::eof())
                && (rc = false);
            traits::eq_int_type(this->sb2_->sputc(c), traits::eof())
                && (rc = false);
        }
        return rc? traits::not_eof(c): traits::eof();
    }
    int sync() {
        bool rc(true);
        this->sb1_->pubsync() != -1 || (rc = false);
        this->sb2_->pubsync() != -1 || (rc = false);
        return rc? 0: -1;
    }
};

#include <fstream>
#include <iostream>

int main()
{
    std::ofstream fout("tee.txt");
    teebuf        sbuf(fout.rdbuf(), std::cout.rdbuf());
    std::ostream  out(&sbuf);
    out << "hello, world!\n";
}

明らかに、ティーストリームの作成はうまくパッケージ化できますが、これがどのように見えるかは実際には重要ではありません。重要なことは、IOStreamのカスタム宛先(またはソース)を作成することが可能であり、から継承する試みを含まないことstd::ostreamです。std::ostream(または)から継承する唯一の理由std::istreamは、カスタムストリームバッファを使用したスト​​リームの初期化を容易にするためです。

于 2012-12-02T00:28:08.533 に答える
6

問題

ofstream::operator << (var);

これは、修飾された関数呼び出しofstream::operator<<としての使用です。関数ルックアップが;のメンバー関数を見つけることを義務付けています。メンバーである最適な一致はの1つですが、実際の文字列の内容を出力するための特殊化はフリー関数です(つまり、メンバー関数ではありません)。ofstreamvoid*char*

これをで行うと、同じ問題が発生しますcout

std::cout.operator<<(var);

ソリューション

これはそれをするかもしれません:

static_cast<ofstream&>(*this) << var;

(これに伴うすべての過負荷解決を使用して)通常の演算子構文を使用しているためですがofstream、LHSオペランドとしてを使用しています。

ただし、実際にはテストしていません。

結論

余談ですが、この慣習に適合するためには、あなた operator<<も自由な機能でなければなりません。

それで:

struct OutputAndConsole : std::ofstream
{
    OutputAndConsole(const std::string& fileName)
       : std::ofstream(fileName)
       , fileName(fileName)
    {};

    const std::string fileName;
};

template <typename T>
OutputAndConsole& operator<<(OutputAndConsole& strm, const T& var)
{
    std::cout << var;
    static_cast<std::ofstream&>(strm) << var;
    return strm;
};

また、構文を少し調整する自由もありました。

于 2012-12-02T00:09:23.610 に答える