7

我正在用 C++ 编写一个日志类。这个类是一个单例。我想以这种方式添加日志:

Log::GetInstance() << "Error: " << err_code << ", in class foo";

好的,在 Log 对象中,我想在最后一个参数出现时保存整行(在本例中为“,在类 foo 中”)。

如何检测最后一个 << 参数?<< a << b << is_this_last << 也许_this_is << or_not。

我不使用任何结束标签。

4

7 回答 7

18

您可以通过不使用单例来解决此问题。如果你做一个这样的函数:

Log log()
{
    return Log();
}

您可以使用几乎与之前相同的方式添加日志:

log() << "Error: " << err_code << ", in class foo";

不同之处在于Log对象的析构函数在这一行之后被调用。所以现在你有一种方法可以检测最后一个参数何时被处理。

于 2010-08-16T20:53:10.460 回答
9

我会让你Log::GetInstance返回一个代理对象而不是日志对象本身。代理对象将保存写入它的数据,然后在其析构函数中,它实际上会将累积的数据写入日志。

于 2010-08-16T20:55:10.987 回答
5

您使 Log 在运算符 << 之后返回不同的对象。

template<typename T>
LogFindT operator<<(Log aLog, T const& data)
{
    // Put stuff in log.
    log.putStuffInLog(data);

    // now return the object to detect the end of the statement.
    return LogFindT(aLog);
}


struct LogFindT
{
    LogFindT(Log& aLog) : TheLog(aLog) {}
    Log& TheLog;
    ~LogFindT()
    {
        // Do stuff when this object is eventually destroyed
        // at the end of the expression.
    }
};

template<typename T>
LogFindT& operator<<(LogFindT& aLog, T const& data)
{
     aLog.TheLog.putStuffInLog(data);

     // Return a reference to the input so we can chain.
     // The object is thus not destroyed until the end of the stream.
     return aLog;
}
于 2010-08-16T21:00:45.173 回答
4

我认为 Jerry 和 Martin 给出了最好的建议,但为了完整起见,我首先想到的是std::endl.

如果您通过自定义类Log在系统内实现,那么您可以简单地在行尾添加或。既然你问了,我想你没有。iostreamstreambuf<< endl<< flush

但是你可以模仿工作方式endl。添加一个操纵器处理程序

Log &operator<< ( Log &l, Log & (*manip)( Log & ) )
    { return manip( l ); } // generically call any manipulator

Log &flog( Log &l ) // define a manipulator "flush log"
    { l->flush(); return l; }

或添加专用operator<<

struct Flog {} flog;

Log &operator<< ( Log &l, Flog )
    { l->flush(); return l; }
于 2010-08-16T21:24:17.983 回答
1

不要对你的操作员太聪明。在有意义的情况下,您应该重载运算符。在这里你不应该。这看起来很奇怪。

您应该只有一个如下所示的静态方法:

Log::Message( message_here );

它需要一个 std::string。然后,客户会为弄清楚如何组装错误字符串而头疼。

于 2010-08-16T20:58:00.853 回答
0

没有什么好方法可以做你想做的事。C 和 C++ 根本不是面向行的语言。没有像“代码行”或任何更大的单元,也没有以任何方式组合的链式调用。

在 C++ 中,表达式“a << b << c << d” 完全等同于对 operator<< 的三个单独调用,如下所示:

 t1 = a;
 t2 = t1.operator<<(b);
 t3 = t2.operator<<(c);
 t4 = t3.operator<<(d);

这就是 C++ ostream 使用 endl 作为显式行尾标记的原因。否则就没有像样的方法。

于 2010-08-16T21:46:47.987 回答
0

这是基于@martin-york 回答的解决方案。稍作修改以在结构中使用成员运算符。

#include<sstream>
#include<iostream>

struct log_t{
    void publish(const std::string &s){
        std::cout << s << std::endl;
    }
};

struct record_t{

    struct record_appender_t
    {
        record_appender_t(record_t& record_) : record(record_) {}
        record_t& record;
        ~record_appender_t()
        {
            // Do stuff when this object is eventually destroyed
            // at the end of the expression.
            record.flush();
        }

        template<typename T>
        record_appender_t& operator<<(T const& data)
        {
            record.stream() << data;
            // Return a reference to the input so we can chain.
            // The object is thus not destroyed until the end of the stream.
            return *this;
        }
    };

    std::ostringstream message;
    log_t log;
    void flush(){
        log.publish(message.str());
    }
    std::ostringstream& stream() {
        return message;
    }
    template<typename T>
    record_appender_t operator<<(T const& data)
    {
        // Put stuff in log.
        message << data;

        // now return the object to detect the end of the statement.
        return record_appender_t(*this);
    }
};

#define LOG \
    record_t()

int main(){
    LOG << 1 << 2 << "a";
}
于 2021-03-18T07:24:56.477 回答