1

I have simple logging class as below.

#include <iostream>
#include <string>

using namespace std;

class log
{
public:
    log(){};
    ~log(){};
    log & operator << ( int x ){ cout << x; return * this;}
    log & operator << ( string x ){ cout << x; return * this;}
    log & operator << ( log & (log::*pf)() ){ (this->*pf)(); return * this;}
    log & end( ) { cout << "\r\n"; return * this;}
};

log l;

#define end             &log::end;
#define error( z )      l << "ERROR " z << end;
#define warn( z )       l << "WARN " z << end;

int main()
{
    int y = 20;

    error ( << y );
}

Is there any way that I can write my code in main like this?

error << y;

Basic idea here, is to avoid user to use macro end

i.e. I do not want user to code like below

error << y << end;
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Sandy
  • 159
  • 1
  • 2
  • 15
  • 7
    Why on Earth do you want to do this? Use the `<<` operator as it was intended. Or just provide `error()` and `warn()` functions that output the desired prefix. There is no need for macros here! – TypeIA Feb 05 '14 at 17:15
  • You might want to have a look at [boost.log](http://www.boost.org/doc/libs/1_55_0/libs/log/doc/html/index.html). – Florian Sowade Feb 05 '14 at 17:17
  • why not deriving the class log from ostream and overload the operator <<, so that just in that given context behaves that way? – jpmuc Feb 05 '14 at 17:19
  • 1
    This is just C++; it has nothing to do with C. The `'\r'` is unnecessary and possibly harmful; text output automatically converts `'\n'` to the appropriate end-of-line representation. I hope you don't need `#include `, which declares the `log()` function. – Keith Thompson Feb 05 '14 at 17:22

4 Answers4

1

Look like you are reinventing the square wheel to me ! Indeed, there are a lot of logger library out there (boost.log is a good one). Another solution is to have the user write the standard syntax including the call to std::endl:

error << x << std::endl; 
warn << y << std::endl;

You can do that by passing a string "warn" or "error" to the construtor of class log. You have to intercept the std::endl parameter as described in Overload handling of std::endl?.

Community
  • 1
  • 1
hivert
  • 10,579
  • 3
  • 31
  • 56
0

What about:

#define LOG(Msg) do { l << Msg << ::std::endl; } while(0)

Log("Hello" << "World");

Note: I use a macro like this in debug builds and make it ((void)0) in release builds.

For common logging you should not use a macro and may consider stream manipulators.

0

One option would be to remove your global variable and use your destructor to write the newline by having the macros create a scope so the object is destroyed:

#define error( z )      {log l; l << "ERROR " z; }
#define warn( z )       {log l; l << "WARN " z; }

That would yield code close to what it appears you want without your end macro:

int y = 20, z = 40;
error ( << y << " " << z);

If you like that approach you might want to look into improving the macro so log levels are enforced in the macro itself so objects are not created with every log message that have nothing to do, if performance at that level matters to you.

Don't see a plug for POCO logging anywhere in here, that's what I use. Not saying that would work for you, it's just what I like for my particular needs.

0

You may create class:

class PrefixLog
{
public:
    explicit PrefixLog(const char* prefix) : prefix(prefix) {}
    template <typename T>
    log& operator << (const T& t) const { return l << prefix << t << &log::end; }
private:
    const char* prefix;
};

PrefixLog error("ERROR ");
PrefixLog warning("WARN ");

And then

warning << y;
error << y;
Jarod42
  • 203,559
  • 14
  • 181
  • 302