【问题标题】:custom stream manipulator for class类的自定义流操纵器
【发布时间】:2009-08-25 14:15:42
【问题描述】:

我正在尝试编写一个简单的审计类,它通过运算符

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;

我认识到我的代码中的重载运算符不会返回流对象,但我想知道是否仍然可以使用类似句法的操纵器。目前,编译器将“

感谢您的任何意见, 帕特里克

【问题讨论】:

    标签: c++ stream manipulators


    【解决方案1】:

    要使其工作,您必须为函数添加运算符

     class CAudit
     {
      //...other details here as in original question
    
      CAudit& operator << (CAudit & (*func)(CAudit &))
      {
            return func(*this);
      }
     };
    
     CAudit audit;
     audit << "some text" << CAudit::write;
    

    【讨论】:

      【解决方案2】:

      二元移位运算符和流运算符是同一个运算符。为你的类重载 operator+ 在 std::cout 上写“Hello world”是完全合法的(尽管这是一个非常糟糕的主意)。与 C++ 标准作者决定将流的 operator 你没有写清楚你的问题是什么。我的猜测是编译错误。在这种情况下,最好的办法是引用错误消息。如果我是对的,问题是,您只为 LPCSTR 定义了 operator 你使用“操纵者”这个词,但你误解了一些东西。流的操纵器(来自 STL 的流)是一个函数,它对写入的流执行一些操作。它之所以有效,只是因为这种重载:

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

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

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

      【讨论】:

        【解决方案3】:

        不是这样

        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;
        };
        

        做你想做的事?

        【讨论】:

        • 感谢您的回答,看起来它的工作方式与 robson 的回答类似,可能会尝试使用仿函数来摆脱函数指针参数。
        【解决方案4】:

        我做了一些非常相似的跟踪,但使用stringstream。这可确保所有第 3 方 operator &lt;&lt; () 和操纵器都能正常工作。我也使用析构函数而不是客户写操纵器。

        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 语句意味着除非您确实需要它,否则您没有构建跟踪行的开销。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-06-02
          • 1970-01-01
          • 2012-10-11
          • 1970-01-01
          • 1970-01-01
          • 2010-10-22
          • 2010-10-06
          • 1970-01-01
          相关资源
          最近更新 更多