类的自定义流操纵器

时间:2009-08-25 14:15:42

标签: c++ stream manipulators

我正在尝试编写一个简单的审计类,它通过运算符<<并在收到如下自定义操纵器后写入审核:

class CAudit
{
public:
    //needs to be templated
    CAudit& operator << ( LPCSTR data ) {
        audittext << data;
        return *this;
    }

    //attempted manipulator
    static CAudit& write(CAudit& audit) { 
        //write contents of audittext to audit and clear it
        return audit; 
    }

private:
    std::stringstream audittext;
};

//to be used like
CAudit audit;
audit << "Data " << data << " received at " << time << CAudit::write;

我认识到我的代码中的重载运算符不返回流对象,但是想知道是否仍然可以使用类似语法的操作符。目前编译器正在看到'&lt;&lt;&lt;作为二元右移算子。

感谢任何输入, 帕特里克

4 个答案:

答案 0 :(得分:4)

要使其工作,您必须添加运算符的重载&lt;&lt;对于功能, 而不是从它调用函数:

 class CAudit
 {
  //...other details here as in original question

  CAudit& operator << (CAudit & (*func)(CAudit &))
  {
        return func(*this);
  }
 };

 CAudit audit;
 audit << "some text" << CAudit::write;

答案 1 :(得分:2)

二元移位运算符和流运算符是同一个运算符。重载operator +让你的类在std :: cout上写“Hello world”是完全合法的(尽管这是一个非常糟糕的主意)。与C ++标准作者决定重载运算符&lt;&lt;对于流写入流 你没有写清楚你的问题是什么。我的猜测是编译错误。在这种情况下最好的事情是引用错误消息。如果我是对的,问题是,你只定义了运算符&lt;&lt;对于LPCSTR,然后你希望它在右侧工作功能对象 你使用“操纵者”这个词,但你误解了一些东西。流的操纵器(来自STL的流)是对其写入的流执行某些操作的功能。它只是因为这种过载而起作用:

ostream& operator<< (ostream& ( *pf )(ostream&));

接受一个函数并将其应用于流 同样你需要:

CAudit& operator<< (CAudit& ( *pf )(CAudit& audit))
{
  return (*pf)(audit);
}

答案 2 :(得分:1)

不会这个

class CAudit
{
public:
    template< typename T >
    CAudit& operator<<( const T& data )
    {
        audittext << data;
        return *this;
    }

    class write {};

    void operator<<( const write& data )
    {
        /* whatever */
    }

private:
    std::stringstream audittext;
};

做你想做的事?

答案 3 :(得分:1)

我为跟踪做了类似的事情,但使用了stringstream。这可确保所有第三方operator << ()和操纵器都能正常工作。我也使用析构函数而不是客户编写操纵器。

class DebugStream
{
public:
    DebugStream(short level, const char * file, int line) {
        sstream << "L" << level << "\t" << file << "\t" << line << "\t";
    }
    ~DebugStream() { write(sstream.str()); }

    std::ostream & stream() { return sstream; }
private:
    std::stringstream sstream;

    DebugStream(const DebugStream &);
    DebugStream & operator=(const DebugStream &);
};

然后可以使用一些宏:

#define DBG_ERROR if (1<=dbg_level()) DebugStream(1, __FILE__, __LINE__).stream()
#define DBG_INFO  if (2<=dbg_level()) DebugStream(2, __FILE__, __LINE__).stream()

代码只使用宏

DBG_INFO << "print some debug information";

您不需要特定的写操纵器来将数据刷新到日志文件。当匿名DebugStream对象超出范围时(一旦控件离开该行),内容将自动写入。

虽然在这种情况下我通常会避免使用宏,但if语句的使用意味着您没有构建跟踪线的开销,除非您确实需要它。

通过ostream方法返回stream()使其能够用于全局成员函数,因为匿名对象不能作为非const引用参数传递。