Logging class and overloaded stream operators [question #2]

R

Riku Jarvinen

Hi everyone,

I asked another question regarding this same subject about a week ago. See
thread:

http://groups.google.fi/group/comp....579d6832732/530bae667a479add#530bae667a479add

So, the basic idea is to have a compact logger class which can be used like
the std::cout stream and add extra functionality to it (line numbering, some
output counters etc.).

The class should also accept the iostream manipulators, including special
manipulators in <iomanip>. How can I make the logging class handle all the
manipulators in the same way std::cout does?

If I compile the code (see below) which tries to use the manipulators with
the Logger class, I get the following error messages:
g++ example2.cpp

example2.cpp: In function `int main()':
example2.cpp:51: error: no match for 'operator<<' in 'mainlog <<
std::setw(int)()'
example2.cpp:22: error: candidates are: Logger& Logger::eek:perator<<(const
char*)
example2.cpp:28: error: Logger& Logger::eek:perator<<(double)
example2.cpp:52: error: no match for 'operator<<' in '
(+(&mainlog)->Logger::eek:perator<<(" x = "))->Logger::eek:perator<<(x) <<
std::endl'
example2.cpp:22: error: candidates are: Logger& Logger::eek:perator<<(const
char*)
example2.cpp:28: error: Logger& Logger::eek:perator<<(double)
example2.cpp:53: error: `precision' undeclared (first use this function)
example2.cpp:53: error: (Each undeclared identifier is reported only once
for
each function it appears in.)
example2.cpp:54: error: no match for 'operator<<' in '
(&mainlog)->Logger::eek:perator<<("x = ") << std::showpos'
example2.cpp:22: error: candidates are: Logger& Logger::eek:perator<<(const
char*)
example2.cpp:28: error: Logger& Logger::eek:perator<<(double)


Simplified example code:

------------------------------------
#include <iostream>
#include <fstream>
#include <iomanip>

using namespace std;

class Logger
{
public:
Logger(const char* filename = "program.log")
{
logfile = new fstream(filename, fstream::eek:ut);
}

~Logger()
{
logfile->close();
delete logfile;
}

Logger& operator<<(const char* msg)
{
*logfile << msg;
return *this;
}

Logger& operator<<(const double val)
{
*logfile << val;
return *this;
}

private:
fstream* logfile;
};

int main()
{
Logger mainlog;
double x = 12.34567;

// These work fine
cout << setw(20) << setfill('*') << setprecision(4);
cout << " x = " << x << endl;
cout.precision(2);
cout << "x = " << showpos << scientific << x << endl;

mainlog << "x = " << x << "\n";

// These don't work
//mainlog << setw(20) << setfill('*') << setprecision(4);
//mainlog << " x = " << x << endl;
//mainlog.precision(2);
//mainlog << "x = " << showpos << scientific << x << endl;

return 0;
}
 
K

Kai-Uwe Bux

Riku said:
Hi everyone,

I asked another question regarding this same subject about a week ago. See
thread:

http://groups.google.fi/group/comp....579d6832732/530bae667a479add#530bae667a479add

So, the basic idea is to have a compact logger class which can be used
like the std::cout stream and add extra functionality to it (line
numbering, some output counters etc.).

The class should also accept the iostream manipulators, including special
manipulators in <iomanip>. How can I make the logging class handle all the
manipulators in the same way std::cout does?

If I compile the code (see below) which tries to use the manipulators with [snip]


Simplified example code:

------------------------------------
#include <iostream>
#include <fstream>
#include <iomanip>

using namespace std;

class Logger
{
public:
Logger(const char* filename = "program.log")
{
logfile = new fstream(filename, fstream::eek:ut);
}

~Logger()
{
logfile->close();
delete logfile;
}

Logger& operator<<(const char* msg)
{
*logfile << msg;
return *this;
}

Logger& operator<<(const double val)
{
*logfile << val;
return *this;
}

what about replacing all these by a template:

template < typename T >
Logger& operator<< ( T const & t ) {
*logfile << val;
return *this;
}

This should handle the manipulators, too. (not tested!)
private:
fstream* logfile;
};

int main()
{
Logger mainlog;
double x = 12.34567;

// These work fine
cout << setw(20) << setfill('*') << setprecision(4);
cout << " x = " << x << endl;
cout.precision(2);
cout << "x = " << showpos << scientific << x << endl;

mainlog << "x = " << x << "\n";

// These don't work
//mainlog << setw(20) << setfill('*') << setprecision(4);
//mainlog << " x = " << x << endl;
//mainlog.precision(2);
//mainlog << "x = " << showpos << scientific << x << endl;

return 0;
}


Best

Kai-Uwe Bux
 
R

Riku Jarvinen

Kai-Uwe Bux said:
Code:
what about replacing all these by a template:

template < typename T >
Logger& operator<< ( T const & t ) {
*logfile << val;
return *this;
}

This should handle the manipulators, too. (not tested!)
[/QUOTE]

I tried this typename template and it didn't seem to help in the manipulator 
issue. I think I can add something like:

Logger& Logger::operator<<(ios_base& (*pf)(ios_base&))
{
   *logfile << pf;
   return *this;
}

but this works only with the manipulators in ios_base and, for example, 
precision is a member function of ios_base, not a manipulator. Any thoughts?

Riku
 
K

Kai-Uwe Bux

Riku said:
Kai-Uwe Bux said:
Code:
what about replacing all these by a template:

template < typename T >
Logger& operator<< ( T const & t ) {
*logfile << val;
return *this;
}

This should handle the manipulators, too. (not tested!)
[/QUOTE]

I tried this typename template and it didn't seem to help in the
manipulator issue. I think I can add something like:[/QUOTE]

The only issue I see is the use of std::endl. Have a look at:


#include <iostream>
#include <fstream>
#include <iomanip>

using namespace std;

class Logger
{
 public:
  Logger(const char* filename = "program.log")
  {
    logfile = new fstream(filename, fstream::out);
  }
  
  ~Logger()
  {
    logfile->close();
    delete logfile;
  }

  template < typename T >
  Logger& operator<<( T const & t ) 
  {
    *logfile << t;
    return *this;
  }

  void precision ( unsigned long p ) {
    *logfile << std::setprecision( p );
  }
  
 private:
  fstream* logfile;
};

int main()
{
  Logger mainlog;
  double x = 12.34567;
  
  // These work fine
  cout << setw(20) << setfill('*') << setprecision(4);
  cout << " x = " << x << endl;
  cout.precision(2);
  cout << "x = " << showpos << scientific << x << endl;
  
  mainlog << "x = " << x << "\n";
  mainlog << setw(20) << setfill('*') << setprecision(4);
  mainlog << " x = " << x << '\n';
  mainlog.precision(2);
  mainlog << "x = " << showpos << scientific;
  mainlog << x << '\n';
  
  return 0;
}

[QUOTE]
Logger& Logger::operator<<(ios_base& (*pf)(ios_base&))
{
*logfile << pf;
return *this;
}

but this works only with the manipulators in ios_base and, for example,
precision is a member function of ios_base, not a manipulator. Any
thoughts?[/QUOTE]

See above. However, I do not yet have an idea about how to deal with endl.



Best

Kai-Uwe Bux
 
R

Riku Jarvinen

Kai-Uwe Bux said:
The only issue I see is the use of std::endl. Have a look at:

Ok, thanks!

I think I have to include separately every member function of std::eek:stream,
std::ios and std::ios_base in the Logger class if I want to make it exactly
like std::cout?
However, I do not yet have an idea about how to deal with endl.

Actually, this (and all the other basic operator<< manipulators) can be
handled with the following addition to the class:

Logger& Logger::eek:perator<<(ostream& (*pf)(ostream&))
{
*logfile << pf;
return *this;
}


Riku
 
T

Thomas J. Gritzan

Hi!

Riku said:
[...]

So, the basic idea is to have a compact logger class which can be used
like the std::cout stream and add extra functionality to it (line
numbering, some output counters etc.).
[...]

Any comments/suggestions are again very welcome!

You could implement a streambuf derived class and and build an ostream
class with it. This ostream then can be used like any other ostream (I
implemented a iostream wrapper for bzip2 library this way).

Thomas
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,819
Latest member
masterdaster

Latest Threads

Top