Question

i'm trying to write a logging class where you will be able to do something like this

//Create an instance of a class
Log log;

log.debug() << "a string " << 42 << endl;
log.info() << "another string " << 41 << endl;

This will produce the following output to stdout

Info: a string 42
Debug: another string 41

Here is what i have been able to achieve so far

#include <iostream>
#include <string>
#include <sstream>

#define endl '\n'

using std::cout;
using std::string;
using std::stringstream;

class Log {
    public:
        Log () {}
       ~Log() {}

        //Create buffer to store everything
        stringstream buffer;

        //Create templase class to overload <<
        template <class T>
        inline Log & operator << (T data) {
                buffer << data;
                return *this;
        }

        inline Log & debug() {
                print("Debug: ");
        } 

        inline Log & info() {
                print("Info: ");
        }

        inline void print(string type) {
                //Display the contents of the buffer to standard output
                cout << type << buffer.str();
                //Clear the buffer
                buffer.str(string());
        }
};

int main() {
        Log log;
        log << "Hello " << "World " << 5 << " " << 2.3 << endl;
        log.debug();

        log << "Hello Again " << 42 << endl;
        log.info();
        return 0;
}

This produces the correct output but this way each line of logging takes up two lines of code and is very cumbersome. Can anyone thing off a way I can do log.debug() << "stuff"? This is a very simple example, in later versions, instead of just a string there will be time stamps, date stamps, usernames etc. which is why i'm trying to get each log level handled by a different function.

I am guessing I'll need another operator overload statement but i just can't figure out what it needs to be. Also the current << template operator doesn't like std::endl (wont compile if i use it) so I just set endl = '\n' at the top.

Thanks in advance, looking forward to learning as much as possible.

Was it helpful?

Solution

It sounds like what you want is for your debug and info functions to return something like a std::stringstream that will support operator<<, but somehow also flush the output afterwards. If that's it, you would be better off using something like a variadic template function.

As for your other issue, std::endl is actually a template, so its type cannot be used as T for Log::operator<< <T> (T). This is one example of why it's not worth trying to reimplement the stream functionality. The overload which lets you write << std::endl is declared something like template <class _CharT, class _Traits> basic_ostream<_CharT, _Traits> & operator<<(basic_ostream<_CharT, _Traits>&, basic_ostream<_CharT, _Traits> &(basic_ostream<_CharT, _Traits> &)). std::endl is a function template which takes an ostream, appends a newline, and flushes the stream.

I should also note that your debug and info functions are not returning a value. If you're using GCC, the warning for this is disabled by default but it can be a very tricky source of undefined behavior. Use -Wreturn-type to enable it when you build something important.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top