4

ここで便利なスタートを見ました:

http://www.cs.technion.ac.il/~imaman/programs/teestream.html

また、clog とログ ファイルの両方に送られる新しいストリームを作成すると、うまく機能します。

ただし、 clog を新しいストリームに再定義しようとしても、新しいストリームには clog と同じ rdbuf() があるため、機能しません。したがって、以下は効果がありません。

clog.rdbuf(myTee.rdbuf());

では、clog のターゲットとなる独自の rdbuf() を持つように tee クラスを変更するにはどうすればよいでしょうか?

ありがとう。

-ウィリアム

4

4 に答える 4

3

出力を別のストリームに送信する代わりに、tee に std::clog を使用し続けたい場合は、1 レベル下で作業する必要があります。ostream から派生する代わりに、streambuf から派生します。次に、これを行うことができます:

fstream logFile(...);
TeeBuf tbuf(logFile.rdbuf(), clog.rdbuf());
clog.rdbuf(&tbuf);

独自の streambuf クラスを派生させる方法の詳細については、こちらを参照してください。

于 2009-06-03T02:00:28.483 に答える
2

「tee」がrdbufレベルで機能していないため、やろうとしていることをしたくありません。そのため、rdbuf を別のものに設定しても機能せず、出力は 1 つのストリームにのみ送られます。

そこの例に従う必要があります:

例えば

fstream clog_file(...);
xstream clog_x(...);
TeeStream clog(clog_file, clog_x);

次に、元の詰まりの代わりにどこでも詰まりを使用します。

于 2009-06-02T06:59:57.540 に答える
1

これが私が作成したクラスで、助けてくれたすべての人に感謝します。

-ウィリアム

class TeeStream : public std::basic_filebuf<char, std::char_traits<char> >
{
private:
  class FileStream : public std::ofstream {
  public:
    FileStream()
      : logFileName("/my/log/file/location.log") {
      open(logFileName.c_str(), ios::out | ios::trunc);

      if (fail()) {
        cerr << "Error: failed to open log file: " << logFileName << endl;
        exit(1);
      }
    }
    ~FileStream() {
      close();
    }

    const char *getLogFileName() const {
      return logFileName.c_str();
    }

  private:
    const string logFileName;

  };

public:
  typedef std::char_traits<char> traits;
  typedef std::basic_filebuf<char, traits> baseClass;

  TeeStream()
    :  baseClass(),
       _logOutputStream(),
       _clogBuf(clog.rdbuf()),
       _fileBuf(_logOutputStream.rdbuf()) {
    clog.rdbuf(this);
    _logOutputStream << "Log file starts here:" << endl;
  }
  ~TeeStream() {
    clog.rdbuf(_clogBuf);
  }

  int_type overflow(char_type additionalChar =traits::eof()) {
    const int_type eof = traits::eof();
    const char_type additionalCharacter = traits::to_char_type(additionalChar);
    const int_type result1 = _clogBuf->sputc(additionalCharacter);
    const int_type result2 = _fileBuf->sputc(additionalCharacter);

    if (traits::eq_int_type(eof, result1)) {
      return eof;
    } else {
      return result2;
    }
  }

  int sync() {
    const int result1 = _clogBuf->pubsync();
    const int result2 = _fileBuf->pubsync();

    if (result1 == -1) {
      return -1;
    } else {
      return result2;
    }
  }

private:
  FileStream _logOutputStream;
  streambuf * const _clogBuf;
  streambuf * const _fileBuf;

};
于 2009-06-04T03:54:49.010 に答える
1

Boost iostreams を使用してそれを行うだけです。

#include <iostream>
#include <fstream>
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>

int main(const int a_argc, const char *a_args[])
{
    namespace io = boost::iostreams;
    typedef io::tee_device<std::ofstream, std::ostream> TeeDevice;
    typedef io::stream<TeeDevice> TeeStream;

    std::ofstream flog("logFile.txt");
    //We need to copy clog, otherwise we get infinite recursion
    //later on when we reassign clog's rdbuf.
    std::ostream clogCopy(std::clog.rdbuf());

    TeeDevice logTee(flog, clogCopy);
    TeeStream logTeeStream(logTee);

    logTeeStream << "This text gets clogged and flogged." << std::endl;

    //Modify clog to automatically go through the tee.
    std::streambuf *originalRdBuf = std::clog.rdbuf(logTeeStream.rdbuf());  

    std::clog << "This text doesn't only get clogged, it's flogged too." << std::endl;

    std::clog.rdbuf(originalRdBuf);
    std::clog << "This text avoids flogging." << std::endl;
}

于 2009-06-14T10:27:11.707 に答える