Own Variant of cout

D

Dennis Lubert

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi people,

I want to create my own variant of a cout Object, so that I can use
different of those for debugging...

Like this class, but as a stream...

class Log
{
private:
static int system_debuglevel;
int debuglevel;
public:
Log( int dl ) : debuglevel(dl) { }
void logthis( const char * msg)
{
if ( debuglevel <= system_debuglevel ) printf("%s", msg);
}

}

So that I can create global objects like those :

Debug(5);
Info(4);
Warn(3);
Error(2);

and can then do Debug << "DEBUGMESSAGE" << endl; with every kind of
object that has a ostream& operator<<()..
So I could need some help with this, I have tried to derive the
logger from ostream, I have tried template functions, but nothing
works really good... the class should then do the output decision for
Debug << "String" << 5 << 4.5f << endl; correctly, but it always
outputs only String, or always 5 and 4.5 regardless whaat
system_debuglevel is set... I could need some help...

greets

Dennis

-----BEGIN PGP SIGNATURE-----
Version: PGP 7.0.1

iQA/AwUBP4VyFhL69PVFlLwmEQLhswCgtBt1938ibhAXIKdiRjEDan1AYwsAn0Nq
UUT+Cq0VLMAq9pRd9twbtN0C
=fsht
-----END PGP SIGNATURE-----
 
I

Ivan Vecerina

Hi Dennis,
| I want to create my own variant of a cout Object, so that I can use
| different of those for debugging...
|
| Like this class, but as a stream...
|
| class Log
| {
| private:
| static int system_debuglevel;
| int debuglevel;
| public:
| Log( int dl ) : debuglevel(dl) { }
| void logthis( const char * msg)
| {
| if ( debuglevel <= system_debuglevel ) printf("%s", msg);
| }
|
| }
....
| and can then do Debug << "DEBUGMESSAGE" << endl; with every kind of
| object that has a ostream& operator<<()..
| So I could need some help with this, I have tried to derive the
| logger from ostream, I have tried template functions, but nothing
| works really good... the class should then do the output decision for
| Debug << "String" << 5 << 4.5f << endl; correctly, but it always
| outputs only String, or always 5 and 4.5 regardless whaat
| system_debuglevel is set... I could need some help...

Try adding the following public member function to the Log class
as it is defined above:

template<typename T>
Log& operator<<(const T& param)
{
if ( debuglevel <= system_debuglevel )
cout << param;
return *this;
}

I would expect this to work.
If it doesn't, please let me know what the behavior is...


hth - Ivan
 
M

Moonlit

Hi,

I think you should be able to derive a class from ostream but then you have
to correctly interface with the ostream buffers I think.

An easier way is to forget about the ostream and use the class you now have.
Then pull all the streaming functions into your class with a template memer
function (goes in the header of course)

class CEnd
{
};
extern CEnd End;

template<class T> CLog& opeartor<<( T Value )
{
if( DebugLevel < SystemDebugLevel ) cerr << Value;
}

template<> CLog& operator<<( CEnd& End )
{
cerr << endl;
}

.... Some more specializations if you want

I do this from the top of my head so I might have make a mistake somewhere.
Now you can use your code but should use End instead of endl

This is the way I do it in my programs.

Regards, Ron AF Greve
 
T

Thomas Matthews

Moonlit said:
Hi,

I think you should be able to derive a class from ostream but then you have
to correctly interface with the ostream buffers I think.

An easier way is to forget about the ostream and use the class you now have.
Then pull all the streaming functions into your class with a template memer
function (goes in the header of course)

class CEnd
{
};
extern CEnd End;

template<class T> CLog& opeartor<<( T Value )
{
if( DebugLevel < SystemDebugLevel ) cerr << Value;
}

template<> CLog& operator<<( CEnd& End )
{
cerr << endl;
}

... Some more specializations if you want

I do this from the top of my head so I might have make a mistake somewhere.
Now you can use your code but should use End instead of endl

This is the way I do it in my programs.

Regards, Ron AF Greve

1. Don't top-post. Top-posting is where you put your response "on top"
of the original post. Replies are either interspersed or appended
to the bottom. Please fix your newsreader.

2. See this link:
http://www.jelovic.com/articles/stupid_naming.htm

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
K

Karl Heinz Buchegger

Dennis said:
So I could need some help with this, I have tried to derive the
logger from ostream,

This is often not what you want to do.
But instead you want to replace the stream's streambuffer.
Every stream object contains a streambuffer object.
While the stream object is repsonsible for formatting the output,
the streambuffer object is responsible for the actual data transfer.

Search for posts or web pages written by 'Dietmar Kuehl'.
He has written some posts on how to write such a beast.
eg. http://groups.yahoo.com/group/boost/message/2511
 
I

Ivan Vecerina

Just a couple comments on the code you posted...
| An easier way is to forget about the ostream and use the class you now
have.
| Then pull all the streaming functions into your class with a template
memer
| function (goes in the header of course)
|
| class CEnd
| {
| };
| extern CEnd End;
|
| template<class T> CLog& opeartor<<( T Value )

It might be better to use T const& instead of T as a parameter type,
to avoid creating an unnecessary intermediate copy of the passed value.

| {
| if( DebugLevel < SystemDebugLevel ) cerr << Value;
return *this; // was missing here
| }
|
| template<> CLog& operator<<( CEnd& End )
| {
| cerr << endl;
return *this; // was missing here
| }
|
| ... Some more specializations if you want
|
| I do this from the top of my head so I might have make a mistake
somewhere.
| Now you can use your code but should use End instead of endl

Note that it should be possible to support std::endl instead of
using your own dedicated class.

I believe a templated operator<< will accept manipulators such as std::endl.
And when a specialization is needed, the following should do:
CLog& operator<<(ostream& (*pf)(ostream&))
{
cerr << pf; // or: pf(cerr);
// ... specialized behavior here, if needed ...
return *this;
}

Like you, this is off the top of my head -- not tested right now.

Hope this helps,
Ivan
 
D

Dietmar Kuehl

Dennis Lubert said:
So that I can create global objects like those :

Debug(5);
Info(4);
Warn(3);
Error(2);

and can then do Debug << "DEBUGMESSAGE" << endl; with every kind of
object that has a ostream& operator<<()..

.... and you want your output depending on some global resource
"system_debuglevel". Unfortunately, you didn't specify when this
resource is set up but, for my convenience, I assume it is set up
prior to the initialization of the stream objects. In this case,
the class derived from 'std::eek:stream' is actually extremely simple:

int system_debuglevel = 3;

struct logstream {
logstream(int level):
std::eek:stream(level <= system_debuglevel? std::cout.rdbuf(): 0) {
}
};

logstream Debug(5);
logstream Info(4);
logstream Warn(3);
logstream Error(2);

If the "system_debuglevel" can change or not initialized when the
stream objects are constructed, there are effectively two options:

- Set the "system_debuglevel" with a function which installs/removes
stream buffers from you log stream objects (in which case you don't
a class at all; well, actually there is no true need for a class in
the above code: you could make the decision for each initialization).

- If you want to modify "system_debuglevel" freely, without calling a
function, derive a class from 'std::streambuf' which does not buffer
the characters. This class would then swallow the characters when
the system's debug level is too low or send them on to 'std::cout's
debug level otherwise.

The first of these two approaches is much faster.
So I could need some help with this, I have tried to derive the
logger from ostream, I have tried template functions, but nothing
works really good...

That would be because you don't understand how the IOStream classes
work: there is no point in deriving from 'std::eek:stream' other than
setting the object up with some specifically constructed stream buffer.
If you want to change the logic how or where the stream dumps the
characters, you would change the stream buffer within.
 
M

Moonlit

Thomas Matthews said:
1. Don't top-post. Top-posting is where you put your response "on top"
of the original post. Replies are either interspersed or appended
to the bottom. Please fix your newsreader.

Personally I like top posting.

Reason:

I already read the other posts in the thread so I only want to read the
stuff that's added. To prevent me from having to scroll down with every
post; TOPpost.

Now you might have a different opinion but please keep in mind that most of
us live in a free world where one can have is own opinion.

Well it is fun to read. I like to use C<class> for my classes so I can use
<class> for the variables like
CLog Log
But everyone has its own preferences I guess. (and it is nice to see people
who are prepending everything with T so you know who is using microsoft or
borland compilers). (What I do while compiling with g++, I just add a C to
every class, sorry)

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book

For youre convenience I made this a bottom post ;-)

Regards, Ron AF Greve.
 
M

Moonlit

Ivan Vecerina said:
Just a couple comments on the code you posted...
| An easier way is to forget about the ostream and use the class you now
have.
| Then pull all the streaming functions into your class with a template
memer
| function (goes in the header of course)
|
| class CEnd
| {
| };
| extern CEnd End;
|
| template<class T> CLog& opeartor<<( T Value )

It might be better to use T const& instead of T as a parameter type,
to avoid creating an unnecessary intermediate copy of the passed value.

Absolutely right!
| {
| if( DebugLevel < SystemDebugLevel ) cerr << Value;
return *this; // was missing here
| }
|
| template<> CLog& operator<<( CEnd& End )
| {
| cerr << endl;
return *this; // was missing here
| }
|
| ... Some more specializations if you want
|
| I do this from the top of my head so I might have make a mistake
somewhere.
| Now you can use your code but should use End instead of endl

Note that it should be possible to support std::endl instead of
using your own dedicated class.

I believe a templated operator<< will accept manipulators such as std::endl.
And when a specialization is needed, the following should do:
CLog& operator<<(ostream& (*pf)(ostream&))
{
cerr << pf; // or: pf(cerr);
// ... specialized behavior here, if needed ...
return *this;
}

Like you, this is off the top of my head -- not tested right now.

That would be much better, I will try this in my class, I didn't get it
working so I took the easy way out a long time ago. I will use your
suggestion since it is more convenient especaily when switching from Log to
cout as one sometimes do.

Thanks for your recommendations.

Regards, Ron AF Greve.
 
R

Ryan Winter

Moonlit said:
For youre convenience I made this a bottom post ;-)

Regards, Ron AF Greve.

Its just easier if you bottom post, otherwise you get all the post
nazi's bleeting about it.

:)

Ryan
 
F

Frank Schmitt

Moonlit said:
Personally I like top posting.

Reason:

I already read the other posts in the thread so I only want to read the
stuff that's added. To prevent me from having to scroll down with every
post; TOPpost.

That's just YOU - how about people who didn't read the previous post?
Apart from that: PLEASE learn to trim the messages you are replying to,
keeping only the important parts.
(Interistingly, in my experience most people who insist on top posting
also don't trim messages - but YMMV)

A: Top posting
Q: What's the most annoying thing on Usenet?

Enough said.

regards
frank
 
G

Gavin Deane

Moonlit said:
Personally I like top posting.

Reason:

I already read the other posts in the thread so I only want to read the
stuff that's added. To prevent me from having to scroll down with every
post; TOPpost.

The need for excessive scrolling can be avoided by snipping the post
to which you are replying and keeping only enough for context.
Arguably, Thomas could have done that when he replied to you (although
he needed to keep some of your post for context for his class naming
link).

Although it doesn't affect me (since I am here courtesy of Google,
which seems to be several hours behind reality), I have seen pointed
out a number times that the nature of message propogation around the
world on usenet is such that you can't assume someone reading your
message has already read the message to which you are replying.

A complicated technical discussion, involving several successive
posts, is a lot easier to follow with unnecessary content snipped and
replies following or interleaved with the parts of the previous
message to which they apply.

Reason:

Personally I don't like top posting.

GJD
 
D

Dennis Lubert

First of all, thanks for the many answers

Dietmar Kuehl said:
That would be because you don't understand how the IOStream classes
work: there is no point in deriving from 'std::eek:stream' other than
setting the object up with some specifically constructed stream buffer

I guess my problem from now on is this buffer... and I really don't fully
understand the streaming stuff
If you want to change the logic how or where the stream dumps the
characters, you would change the stream buffer within.

Could you give me a hint how to do this ??

I have written the following stuff so far. Somone asked for the
system_debuglevel. It MUST be changeable after the creation of the
debug-stream objects, and they must then behave according to the new one. I
would expect the following output from my main :

hello world 123 0.5\n
hello world 123 0.5\n

But what I get is :

hello world hello world

well, at least for the first string, it seems to work, that it reacts
according to the debuglevel, but where are the 123 and 0.5 and endl ??

Here is my program so far ( I use gcc 3.3 for compiling it )

#include <iostream>
using namespace std;

int system_debuglevel = 5;

class foo : public ostream
{
private:
int debuglevel;

public:
foo( int dl) : ostream(NULL), debuglevel(dl) {}
template <class T> ostream &operator<<(const T &data);
};

template <class T> ostream& foo::eek:perator<<(const T &data) {

// cerr << __PRETTY_FUNCTION__ << std::endl;

if ( debuglevel <= system_debuglevel )
cout << data;

return *this;
}

int main(void) {
foo bar4(4);
foo bar5(5);
foo bar6(6);
bar4 << "hello world " << " " << 123 << " " << 0.5f << endl;
bar5 << "hello world " << " " << 123 << " " << 0.5f << endl;
bar6 << "hello world " << " " << 123 << " " << 0.5f << endl;

cout << endl;
return 0;
}
 
D

Dietmar Kuehl

<veröffentlicht & per Mail versendet>

Dennis said:
I guess my problem from now on is this buffer... and I really don't fully
understand the streaming stuff

I have posted quite a few articles on how to create own stream buffers
over the years. Although rather aged by now, you can find an explanation
of this stuff if you look for IOStreams I have done at Konstanz (eg.
Could you give me a hint how to do this ??

Sure. However, I have posted stuff like this often in the past. Actually
I'm quite sure that I have addressed this particular logging level stuff
before. As indicated in my previous answer, you could do a much better
job when the debug level is maintained via a function because in this
case you can simply set or clear a state bit or the stream buffer in the
respective stream objects: this is both easier and faster (and I think I
have even posted code for this before, too).

Here is my program so far ( I use gcc 3.3 for compiling it )

.... and it doesn't follow my advice given in my previous reply at all!
class foo : public ostream
{ [...]
template <class T> ostream &operator<<(const T &data);
};

I'm positive that I have advised you *NOT* do anything like the above
(the exact statement read "there is no point in deriving from
'std::eek:stream' other than setting the object up with some specifically
constructed stream buffer).
 

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

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,228
Latest member
MikeMichal

Latest Threads

Top