自定义C++操纵器问题

Tom*_*Tom 0 c++ stream manipulators

我正在尝试在我的日志记录类中实现自己的流操纵器.它基本上是改变旗帜状态的终点操纵器.但是,当我尝试使用它时,我会得到:

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>]
Run Code Online (Sandbox Code Playgroud)

...

码:

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;
}
Run Code Online (Sandbox Code Playgroud)

我尝试调用它时收到错误:

log->debug() << "START - object created" << log->endl;
Run Code Online (Sandbox Code Playgroud)

(log是指向Log对象的指针)

有任何想法吗?我怀疑它在某种程度上与操纵者实际上在课堂内的事实有关,但这只是我猜测的......

干杯,

汤姆

编辑:由于限制格式,将此放在这里而不是评论.我试图实现我的streambuf,它有一个例外:当我尝试打开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;
Run Code Online (Sandbox Code Playgroud)

正确添加"测试".

不起作用:

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

抛出异常,如果我将openmode设置为out然后它可以工作..

干杯

str*_*ger 5

定义了一个operator<<(ostream &, ostream &(*)(ostream&))但不是一个operator<<(ostream &, ostream &(Log::*)(ostream&)).也就是说,如果操纵器是普通(非成员)函数,它将起作用,但由于它取决于实例Log,因此正常的重载将不起作用.

要解决此问题,您可能需要log->endl成为辅助对象的实例,并在推送时operator<<调用相应的代码.

像这样:

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) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)