By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,247 Members | 1,250 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,247 IT Pros & Developers. It's quick & easy.

Logging class and overloaded stream operators [question #2]

P: n/a
Hi everyone,

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

http://groups.google.fi/group/comp.l...0bae667a479add

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::operator<<(const
char*)
example2.cpp:28: error: Logger& Logger::operator<<(double)
example2.cpp:52: error: no match for 'operator<<' in '
(+(&mainlog)->Logger::operator<<(" x = "))->Logger::operator<<(x) <<
std::endl'
example2.cpp:22: error: candidates are: Logger& Logger::operator<<(const
char*)
example2.cpp:28: error: Logger& Logger::operator<<(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::operator<<("x = ") << std::showpos'
example2.cpp:22: error: candidates are: Logger& Logger::operator<<(const
char*)
example2.cpp:28: error: Logger& Logger::operator<<(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::out);
}

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

Any comments/suggestions are again very welcome!

Riku

--
life, space, irc

Oct 25 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
Riku Jarvinen wrote:
Hi everyone,

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

http://groups.google.fi/group/comp.l...0bae667a479add
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::out);
}

~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

Oct 25 '05 #2

P: n/a
Kai-Uwe Bux wrote:

[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!)

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


Best

Kai-Uwe Bux


Oct 26 '05 #3

P: n/a
Riku Jarvinen wrote:
Kai-Uwe Bux wrote:

[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!)


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


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

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?


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

Best

Kai-Uwe Bux
Oct 26 '05 #4

P: n/a
Kai-Uwe Bux wrote:
Riku Jarvinen wrote:

I tried this typename template and it didn't seem to help in the
manipulator issue. I think I can add something like:
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::ostream,
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::operator<<(ostream& (*pf)(ostream&))
{
*logfile << pf;
return *this;
}
Riku


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

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?


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

Best

Kai-Uwe Bux


Oct 26 '05 #5

P: n/a
Hi!

Riku Jarvinen schrieb:
[...]

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
Oct 26 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.