0

ロギングクラス内に独自のストリームマニピュレータを実装しようとしています。基本的には、フラグの状態を変更するエンドラインマニピュレータです。ただし、使用しようとすると、次のようになります。

ftypes.cpp:57: error: no match for ‘operator<<’ in ‘log->Log::debug() << log->Log::endl’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/ostream.tcc:67: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/ostream.tcc:78: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/ostream.tcc:90: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]

..。

コード:

class Log {
public:
  ...
  std::ostream& debug() { return log(logDEBUG); }  
  std::ostream& endl(std::ostream& out);           // manipulator
  ...
private:
  ...
  std::ofstream m_logstream;
  bool          m_newLine;
  ...
}


std::ostream& Log::endl(std::ostream& out) 
{  
  out << std::endl;
  m_newLine = true;
  return out;
}

std::ostream& Log::log(const TLogLevel level)
{
  if (level > m_logLevel) return m_nullstream;

  if (m_newLine)
  {
    m_logstream << timestamp() << "|" << logLevelString(level) << "|";
    m_newLine = false;
  }
  return m_logstream;
}

呼び出そうとするとエラーが発生します:

log->debug() << "START - object created" << log->endl;

(logはLogオブジェクトへのポインタです)

何か案は?マニピュレーターが実際にクラス内にあるという事実に何らかの形で関係しているのではないかと思いますが、それは私の大げさな推測です...

乾杯、

トム

編集:フォーマットを制限するため、コメントの代わりにこれをここに置きます。私は自分のstreambufを実装しようとしましたが、1つの例外を除いてうまく機能します。追加のためにfilebufを開こうとすると、失敗します。出力はうまく機能しますが、何らかの理由で追加するだけでは機能しません。追加でofstreamを直接使用しようとすると、機能します。なぜですか?–作品:

std::ofstream test; 
test.open("somefile", std::ios_base::app); 
if (!test) throw LogIoEx("Cannon open file for logging"); 
test << "test" << std::endl;

「テスト」を正しく追加します。

動作しません:

std::filebuf *fbuf = new std::filebuf(); 
if (!fbuf->open("somefile", std::ios_base::app)) throw LogIoEx("Cannon open file for logging"); 

例外をスローします。openmodeをoutに設定すると、機能します。

乾杯

4

3 に答える 3

5

There is defined an operator<<(ostream &, ostream &(*)(ostream&)) but not an operator<<(ostream &, ostream &(Log::*)(ostream&)). That is, the manipulator would work if it were a normal (non-member) function, but because it depends on an instance of Log, the normal overload wouldn't work.

To fix this problem, you may need to have log->endl be an instance to a helper object and, when pushed with operator<<, call the appropriate code.

Like so:

class Log {
  class ManipulationHelper {  // bad name for the class...
  public:
    typedef ostream &(Log::*ManipulatorPointer)(ostream &);

    ManipulationHelper(Log *logger, ManipulatorPointer func) :
      logger(logger),
      func(func) {
    }

    friend ostream &operator<<(ostream &stream, ManipulationHelper helper) {
        // call func on logger
        return (helper.logger)->*(helper.func)(stream);
    }

    Log *logger;
    ManipulatorPointer func;
  }

  friend class ManipulationHelper;

public:
  // ...

  ManipulationHelper endl;

private:
  // ...

  std::ostream& make_endl(std::ostream& out); // renamed
};

// ...

Log::Log(...) {
  // ...
  endl(this, make_endl) {
  // ...
}
于 2009-11-16T04:32:37.747 に答える
2

That's not how manipulators work - it's all about types. What you want is something like:

class Log {
...
struct endl_tag { /* tag struct; no members */ };
static const struct endl_tag endl;
...
LogStream &debug() { /* somehow produce a LogStream type here */ }
}

LogStream &operator<<(LogStream &s, const struct endl_tag &) {
  s.m_newLine = true;
}

Note that:

  1. Since m_newLine is part of Log, we can't be working with generic std::ostreams. After all, what would std::cout << Log->endl() mean? So you need to create a new stream type derived from std::ostream (I've left it out here, but assumed it's named LogStream).
  2. endl doesn't actually do anything itself; all the work is in operator<<. The only purpose of it is to get the right operator<< overload to run.

That said, you're not supposed to be defining new manipulators and stream classes if you can avoid it, because it gets complex :) Can you do what you need using just std::endl, and wrapping an ostream around your own custom streambuf? That is how the C++ IO library is meant to be used.

于 2009-11-16T04:34:03.297 に答える
1

これを試して:

#include <iostream>

class Log
{
    public:
    class LogEndl
    {
        /*
         * A class for manipulating a stream that is associated with a log.
         */
        public:
            LogEndl(Log& p)
                :parent(p)
            {}
        private:
            friend std::ostream& operator<<(std::ostream& str,Log::LogEndl const& end);
            Log&    parent;
    };
    std::ostream& debug()   {return std::cout;}
    /*
     * You are not quite using manipulators the way they are entended.
     * But I wanted to give an example that was close to your original
     *
     * So return an object that has an operator << that knows what to do.
     * To feed back info to the Log it need to keep track of who its daddy is.
     */
    LogEndl       endl()    {return LogEndl(*this);}
    private:
        friend std::ostream& operator<<(std::ostream& str,Log::LogEndl const& end);
        bool    endOfLine;

};


std::ostream& operator<<(std::ostream& str,Log::LogEndl const& end)
{
    // Stick stuff on the stream here.
    str << std::endl;

    // Make any notes you need in the log class here.
    end.parent.endOfLine    = true;

    return str;
};

int main()
{
    Log     log;

    /*
     * Please note the use of objects rather than pointers here
     * It may help
     */
    log.debug() << "Debug " << log.endl();
}
于 2009-11-16T08:55:45.233 に答える