【问题标题】:Create a logging object with std::stream interface [duplicate]使用 std::stream 接口创建日志对象
【发布时间】:2019-02-03 00:09:03
【问题描述】:

在内部,我们有一个带有接口OurLog(const char *) 的日志记录功能。我希望能够使用类似于std::ostringstream 的界面来使用它。换句话说,我很想有一个适配器对象,这样我就可以写:

 logging_class log;
 log << "There are " << num_lights << " lights\n";

这个调用OurLog() 将消息写入日志。

看起来从std::streambuf 派生缓冲区类是正确的方法;怎么做呢?需要实现哪些功能?

【问题讨论】:

  • 也许为你的班级实现operator&lt;&lt; 更容易?

标签: c++ ostream streambuf


【解决方案1】:

如果你想要每一行

log << "There are " << num_lights << " lights\n";

调用您的OurLog(const char *) 那么这个玩具示例可能有助于开始:

struct toy_logger {
    std::stringstream data;
    ~toy_logger() { OurLog(data.c_str()); }
    template <typename T> operator<<(const T& t) { data << t; }
};

在使用上只有细微差别:

toy_logger() << "There are " << num_lights << " lights\n";
        //^ create temporary that will get its destructor called at the end of the line

【讨论】:

    【解决方案2】:

    在 libstdc++ 文档here 中找到了一个简单的示例。

    class LoggingBuffer : public std::streambuf {
    protected:
        virtual int_type overflow (int_type c) {
            if (c != EOF) {
                char msg[2] = {static_cast<char>(c), 0};
                OurLog(msg);
            }
            return c;
        }
    };
    
    class Logger : public std::ostream {
        LoggingBuffer logging_buffer;
    public:
        Logger() : logging_buffer(), std::ostream(&logging_buffer) {}
    
    };
    
    extern Logger log; //instantiated in a cpp file for global use
    

    不幸的是,它看起来性能不佳,因为它需要对每个字符进行函数调用。有没有更有效的方法来做到这一点?

    【讨论】:

    • 这是一般的方法。 std::streambuf 中还有其他可以覆盖的虚函数。首先阅读一些documentation
    【解决方案3】:

    我最近做了类似的事情。根据您的要求(特别是需要冲洗时),有一些不同的方法。

    一个非常简单的方法是简单地继承 std::stringstream (如果你需要一个更简单的工厂函数,然后利用复制省略/RVO)。这将在对象超出范围时写入。

    class LogStream : public std::ostringstream
    {
    public:
      LogStream(){}
    
      ~LogStream()
      {
            log(str());
      }
    };
    

    使用 streambuf 方法,您的基本需求就是覆盖 sync()(也可能是析构函数)。

      virtual int sync() override {
        ::log(str());
        str("");//empty buffer
        return 0;//success
      }
    

    然后用你的 streambuf 实例化 std::ostream。希望对您有所帮助。

    【讨论】:

    • 如果您需要更多信息/详细信息,也许使用 streambuf 方法 (?),请不要犹豫。
    猜你喜欢
    • 1970-01-01
    • 2015-05-21
    • 2019-11-26
    • 2021-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-28
    • 2013-02-06
    相关资源
    最近更新 更多