运算符<< - 如何检测最后一个参数

时间:2010-08-16 20:48:07

标签: c++ logging operator-keyword

我正在用c ++写一个日志类。这个班是一个单身人士。我想以这样的方式添加日志:

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

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

如何检测最后一个&lt;&lt;争论? &LT;&LT; a&lt;&lt; b&lt;&lt; is_this_last&lt;&lt; maybe_this_is&lt;&lt; or_not。

我不使用任何结束标记。

7 个答案:

答案 0 :(得分:17)

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

Log log()
{
    return Log();
}

您可以像以前一样添加日志:

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

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

答案 1 :(得分:9)

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

答案 2 :(得分:4)

在运算符&lt;&lt;之后,使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;
}

答案 3 :(得分:4)

我认为Jerry和Martin给出了最好的建议,但为了完整起见,我想到的第一件事是std::endl

如果您通过自定义Log课程在iostream系统中实施了streambuf,则可以在结尾处添加<< 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; }

答案 4 :(得分:1)

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

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

Log::Message( message_here );

采用std :: string。然后,客户可以清楚地知道如何组装错误字符串。

答案 5 :(得分:0)

没有好办法做你想做的事。 C和C ++根本不是面向行的语言。没有更大的单位,如“代码行”或任何东西,链接的调用也不会以任何方式组合。

在C ++中,表达式“a&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;

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

这就是为什么C ++ ostreams使用endl作为明确的行尾标记;否则就没有办法做到这一点。

答案 6 :(得分: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";
}