开发者

Logging, How to get command end?

开发者 https://www.devze.com 2023-03-29 08:47 出处:网络
So I use such Log class: #include <stdio.h> #include <iostream> class Log { public开发者_如何学JAVA:

So I use such Log class:

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

class Log
{
public开发者_如何学JAVA:
    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;
    }
};

Which I use like:

#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();
}

I want my log class to get when I put ";" meaning if I have a << "here's a message" << std::endl; I want it to be capable to get that it is oune log message and a << "here's one with a number: " << 5; is another.

crently it outputs next message:

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

I want to keep its sintax (unlimited number of <<, big range of value types, no ( and ) around in api) but make it output:

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

How to do such thing?


Make operator<< return a temporary value which will place endl upon destruction and forwards all operator<< calls to the main object. This way, endl is guaranteed to be called exactly once.

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;
    }
};


You can define a special object which, when inserted, indicates the end of the log entry. I know this is not exactly what you want, but it's really easy to implement. It also leaves you the flexibility to spread a log entry over several statements (which is useful for generating parts of a log entry within a loop, for example).

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;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消