【问题标题】:Logging, How to get command end?记录,如何获得命令结束?
【发布时间】:2011-08-17 21:31:47
【问题描述】:

所以我用这样的Log class

#include <stdio.h>
#include <iostream>

class Log
{
public:
    int i;
    Log()
    {
        i = 0;
    }

    template <class T>
    Log &operator<<(const T &v)
    {
        i++;
        std::cout << i << ":"  << v << ";" <<std::endl;
        return *this;
    }
    Log &operator<<(std::ostream&(*f)(std::ostream&)) 
    {
        i++;
        std::cout << i << ":"  << *f << ";" <<std::endl;
        return *this;
    }

    ~Log()
    {
        std::cout << " [end of message]" << std::endl;
    }
};

我使用的是这样的:

#include <log.h>

int main()
{
    Log a;
    a << "here's a message" << std::endl;
    a << "here's one with a number: " << 5;
    std::cin.get();
}

我希望我的日志类在我输入“;”时得到意思是如果我有 a &lt;&lt; "here's a message" &lt;&lt; std::endl; 我希望它能够得到它是一个日志消息,而 a &lt;&lt; "here's one with a number: " &lt;&lt; 5; 是另一个。

它会输出下一条消息:

1:here's a message;
2:
;
3:here's one with a number: ;
4:5;

我想保留它的 sintax(无限数量的 &lt;&lt;,大量的值类型,在 api 中没有 ())但让它输出:

1:here's a message
;
2:here's one with a number: 5;

这样的事情怎么办?

【问题讨论】:

    标签: c++ templates logging stl std


    【解决方案1】:

    使operator&lt;&lt; 返回一个临时值,该值将在销毁时放置endl,并将所有operator&lt;&lt; 调用转发到主对象。这样,endl 就保证被调用一次。

    class Log
    {
    struct EndlOnDeath {
        Log* log;
        EndlOnDeath(Log* ptr)
            : log(ptr) {}
        template<typename T> EndlOnDeath& operator<<(const T& val) {
            (*log) << val;
        }
        ~EndlOnDeath() {
            (*log) << std::endl;
        }
    };
    
    public:
        int i;
        Log()
        {
            i = 0;
        }
    
        template <class T>
        EndlOnDeath operator<<(const T &v)
        {
            i++;
            std::cout << i << ":"  << v << ";";
            return this;
        }
        Log &operator<<(std::ostream&(*f)(std::ostream&)) 
        {
            i++;
            std::cout << i << ":"  << *f << ";" <<std::endl;
            return *this;
        }
    
        ~Log()
        {
            std::cout << " [end of message]" << std::endl;
        }
    };
    

    【讨论】:

    • 确定性破坏是 Teh Epix WinRAR™
    • @DeadMG:主要目的是使划分不是one text line消息而是one code line messages成为可能,例如a &lt;&lt; std::endl &lt;&lt; std::endl &lt;&lt; std::endl &lt;&lt; std::endl;将是一条消息。
    • 这个想法很有趣,但它无法编译=(我得到 C2143 或 C2914 和 C2676
    • 经过多次班克测试后,我们采用了与您的方法非常相似(但线程安全)here.hhere.cpp
    【解决方案2】:

    您可以定义一个特殊对象,当插入该对象时,它会指示日志条目的结束。我知道这不是你想要的,但它很容易实现。它还使您可以灵活地将日志条目分散到多个语句中(例如,这对于在循环中生成部分日志条目很有用)。

    struct LogEnd {};
    const LogEnd logend;
    
    class Log
    {
    public:
        Log() : number_(0) {}
    
        template <typename T> Log& operator<<(const T& x)
        {
            ss_ << x;
        }
    
        Log& operator<<(const LogEnd& aLogEnd)
        {
            // Dump the stringstream string to output with desired decorations.
            std::cout << number_ << ": " << ss_.str() << std::endl;
    
            // Clear the stringstream
            ss_.str("");
    
            ++number_;
        }
    
    private:
        std::ostringstream ss_;
        int number_;
    
    };
    
    int main()
    {
        Log log;
        log << "This is " << 1 << " log entry" << logend;
    }
    

    【讨论】:

    • 这与直接endl 有何不同?
    • 我认为 OP 希望每条日志消息都有一个数字前缀。这不仅仅是在每条日志消息的末尾附加一个换行符的问题。使用编号的日志消息功能编辑答案。
    猜你喜欢
    • 2016-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2012-10-25
    相关资源
    最近更新 更多