【问题标题】:Output to logging class via operator<<通过 operator<< 输出到日志记录类
【发布时间】:2014-12-14 10:16:57
【问题描述】:

我已经实现了一个日志类 TLogFile,现在我想重载输出操作符

TLogFile* log = new TLogFile("some arguments...");
*log << "Hello world."; // (1)
*log << "Hello world." << endl; // (2)
*log << std::hex << setw(2) << setfill('0') << someValue << endl; // (3)

我使用 ostream 作为班级成员和朋友。该类如下所示:

namespace app {

class TLogFile
{
public:
    app::TLogFile& operator<< (std::string& out);
    std::ostream&  operator<< (std::ostream& out);
    friend std::ostream& operator<< (std::ostream& out, TLogFile& o);
};

} // namespace app

只有纯文本 (1) 使用字符串版本。我一使用 endl (2) 或 iomanip (3) 就会收到错误消息:

../src/main.cpp:164:70: 错误:'sysdat.app::cSystemData::obj.app::cSystemObjects::applicationLog->app:: 中的 'operatorsysdat.obj.applicationLog (const std::allocator*)(& std::allocator())))))

我相信其中一个 ostream 版本应该可以工作。 有谁知道如何重载运算符以便可以使用 endl 和 iomanip?

【问题讨论】:

  • std::endl 不是字符串或流。

标签: c++11 stl


【解决方案1】:

您的operator&lt;&lt; 只能接收std::ostream&amp;std::string&amp;
(注意:可能应该是const std::string&amp;)。

我能想到的最优雅的解决方案是写一个模板:

class TLogFile{
protected:
    std::ostream* stream;
public:
    /* default ctor, copy ctor and assignment operator: */
    TLogFile(std::ostream& _stream=std::clog):stream(&_stream){}
    TLogFile (const TLogFile&) =default;
    TLogFile& operator= (const TLogFile&) =default;

    /* std::endl is overloaded,
     * so I think compiler doesn't know which version to use.
     * This funchtion handles function pointers, including std::endl
     */
    inline TLogFile& operator<< (std::ostream&(*func)(std::ostream&)){
        (*stream) << func;
        return *this;
    }        

    /* should handle everything else */
    template<typename T>
    inline TLogFile& operator<< (const T& t) {
        (*stream) << t;
        return *this;
    }
}

See it working in online compiler

这样,您的对象的operator&lt;&lt;s 应该能够获取std::ostream 可以获取的任何东西。

编辑:

下次请说要自定义std::endl

我不确定带有签名的函数

inline TLogFile& operator<< (std::ostream&(*func)(std::ostream&))

std::endl 传递给它时使用。我以前的解决方案似乎不雅,甚至不起作用。我想知道当std::endl 传递给不同类的对象时如何改变它的行为。

注意事项:

  1. In most cases I'd like to use '\n instead of std::endl.

  2. TLogFile* log = new TLogFile("some arguments...");
    

    我认为在这里使用原始指针并不是最好的主意(很容易忘记delete),
    除非您必须明确决定对象何时死亡。

    • 当对象在当前作用域死亡时应该死亡,它应该是一个局部变量:

      TLogFile log("some arguments...");
      //Usage:
      log << "Hello world."; // (1)
      log << "Hello world." << endl; // (2)
      log << std::hex << setw(2) << setfill('0') << someValue << endl; // (3)
      
    • 如果对象在多个地方使用,并且每个地方都独立于其他地方使用它,IMO 最好的解决方案是使用std::shared_ptr

      #include <memory>
      #include <utility>
      auto log=std::make_shared<TLogFile>("some arguments...");
      //Usage:
      *log << "Hello world."; // (1)
      *log << "Hello world." << endl; // (2)
      *log << std::hex << setw(2) << setfill('0') << someValue << endl; // (3)
      

      这样,当最后一个 shared_ptr 发生时,对象就会死亡。

  3. 我在类中使用了指针来重新分配它。如果不需要重新赋值,可以使用reference代替。

【讨论】:

  • 我想知道这行到底是做什么的:new TlogFile(whatever) 返回一个 TLogFile* --- 抱歉,从真实来源中提取它时出错,现在在原帖中更正了。跨度>
  • 感谢模板的提示,我会尝试并返回结果。
  • 我删除了除模板之外的所有运算符。由于没有 endl 或 iomanip,它的工作方式与日志一样。我收到以下错误:../src/main.cpp:164:70: 错误:'sysdat.app::cSystemData::obj.app::cSystemObjects::applicationLog-> 中的 'operator
  • 为什么要实现我们自己的类包装std::ostream
  • 你的意思是日志类应该从ostream派生?
【解决方案2】:

感谢 GingerPlusPlus。我发现,运算符 operator请阅读备注/编辑GingerPlusPlus)。我将 ostream 替换为 stringstream,并在调用运算符时写入 stringstream 的内容。

class TLogFile{
protected:
    std::ostream* stream;
    std::stringstream line;
public:
    /* default ctor, copy ctor and assignment operator: */
    TLogFile(std::ostream& _stream=std::clog):stream(&_stream){}
    TLogFile (const TLogFile&) =default;
    TLogFile& operator= (const TLogFile&) =default;

    void write() {
        // Doing some write stuff
        // ...

        // Empty stringstream buffer
        line.str(std::string());
    }

    /* std::endl is overloaded,
     * so I think compiler doesn't know which version to use.
     * This funchtion handles function pointers, including std::endl
     */
    inline TLogFile& operator<< (std::ostream&(*func)(std::ostream&)){
        line << func;
        write();
        return *this;
    }        

    /* should handle everything else */
    template<typename T>
    inline TLogFile& operator<< (const T& t) {
        line << t;
        return *this;
    }


}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 2016-09-24
    • 1970-01-01
    • 2014-01-11
    • 2014-12-25
    • 1970-01-01
    • 2019-04-24
    相关资源
    最近更新 更多