C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

endl issues for class derived from ostream

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Matthew Walker
Guest





PostPosted: Thu Oct 21, 2004 5:27 pm    Post subject: endl issues for class derived from ostream Reply with quote



Hi,

I am trying to write a debugging (or trace) class. It effectively sits
between cout (or similar) and the user. My problem is that some uses of
endl cause a compiler error.

Can anyone suggest how I might go about solving this issue? Of even
more interest to me would be pointers to resources that cover the
iostream classes.

Thanks in advance,

Matthew Walker

********************************************

#include <iostream>

using namespace std;

class Debug : public std::ostream {
public:
// Default constructor
Debug(): ostream(cout.rdbuf()),
stream(cout)
{}

// Copy constructor (not used in this example)
Debug(const Debug& rhs) : std::ostream( rhs.stream.rdbuf() ),
stream(rhs.stream) {
}

template <class T> std::ostream& operator<<(T data) {
stream << data;
return stream;
}

private:
std::ostream& stream;
};



int main() {
Debug d;
d << "This endl is ok..." << endl;

// d << endl; // Line won't compile when uncommented -- why?
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Ron Natalie
Guest





PostPosted: Fri Oct 22, 2004 5:19 pm    Post subject: Re: endl issues for class derived from ostream Reply with quote



Matthew Walker wrote:
Quote:

d << "This endl is ok..." << endl;

This works because
(d << "This endl is ok...")
has a type of ostream&. You're doing ostream << endl.
Quote:

// d << endl; // Line won't compile when uncommented -- why?
}

Here you're doing
Debug << endl;

endl is itself a template. I suspect you've got too many templates
here for it to deduce what the type is. You might try an explicit
overload for the accessor
std::ostream& operator<<(std::ostream& (*pf)(std::ostream&)) {
return stream << pf;
}


I don't know what your class is trying to do, but I've often
found that it's better to make your class do it's work in
the stream buffer rather than trying to overload all the output
functions.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Matthew Walker
Guest





PostPosted: Fri Oct 22, 2004 5:41 pm    Post subject: Re: endl issues for class derived from ostream Reply with quote



Matthew Walker wrote:
Quote:
I am trying to write a debugging (or trace) class. It effectively sits
between cout (or similar) and the user. My problem is that some uses of
endl cause a compiler error.

After further testing I found that for the line
d << "a" << "b";
the "a" would go through my Debug class, but the "b" would just go
through the standard stream.

I read about streambuf's and implemented the following. Any comments
would be greatfully received.

Matthew Walker

******************************************

#include #include <fstream>
#include <streambuf>

using namespace std;


// A class that effectively dumps any input data just by doing nothing
// with it.
class NullBuf : public std::streambuf
{
protected:
// Central output function: does nothing
virtual int_type overflow (int_type c) {
return c;
}
};



// A debug/trace class that allows debuggin messages to be turned on
// and off at will.
class Debug : public std::ostream {
public:
// Default ctor (based on cout)
Debug() : ostream( cout.rdbuf() ), // debugging on by default
mNullBuf(new NullBuf),
mBuf( cout.rdbuf() )
{
}

// Ctor with ostream
Debug( const std::ostream& stream ) : ostream( stream.rdbuf() ), //
on by default
mNullBuf( new NullBuf ),
mBuf( stream.rdbuf() )
{
}

// Copy ctor
Debug( const Debug& rhs ) : ostream( rhs.rdbuf() ),
mNullBuf( rhs.mNullBuf ),
mBuf( rhs.mBuf )
{
}

// Turn debugging off
void off() {
rdbuf( mNullBuf );
}

// Turn debugging on
void on() {
rdbuf( mBuf );
}

private:
streambuf* mNullBuf;
streambuf* mBuf;
};



int main() {
Debug d;
// d.off(); // Comment out this line to turn debugging off.
d << "Test" << endl;
}

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Sharad Kala
Guest





PostPosted: Fri Oct 22, 2004 5:42 pm    Post subject: Re: endl issues for class derived from ostream Reply with quote


"Matthew Walker" <m.g.walker (AT) NOmassey (DOT) SPac.AMnz> wrote in message
Quote:
********************************************

#include <iostream

using namespace std;

class Debug : public std::ostream {
public:
// Default constructor
Debug(): ostream(cout.rdbuf()),
stream(cout)
{}

// Copy constructor (not used in this example)
Debug(const Debug& rhs) : std::ostream( rhs.stream.rdbuf() ),
stream(rhs.stream) {
}

template stream << data;
return stream;
}

private:
std::ostream& stream;
};


std::endl is a pointer to a function and your class does not handle it.


Quote:
int main() {
Debug d;
d << "This endl is ok..." << endl;

This works because d << "This endl is ok..." returns an std::ostream& .

Quote:
// d << endl; // Line won't compile when uncommented -- why?

Add something like this to your class

typedef ostream& (*manipT)(ostream&);
Debug& operator<< (manipT manip)
{
((*manip)(cout));
return *this;
}

Sharad



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Catalin Pitis
Guest





PostPosted: Fri Oct 22, 2004 5:43 pm    Post subject: Re: endl issues for class derived from ostream Reply with quote


"Matthew Walker" <m.g.walker (AT) NOmassey (DOT) SPac.AMnz> wrote

Quote:
Hi,

I am trying to write a debugging (or trace) class. It effectively sits
between cout (or similar) and the user. My problem is that some uses of
endl cause a compiler error.

Can anyone suggest how I might go about solving this issue? Of even
more interest to me would be pointers to resources that cover the
iostream classes.

Thanks in advance,

Matthew Walker

********************************************

#include <iostream

using namespace std;

class Debug : public std::ostream {
public:
// Default constructor
Debug(): ostream(cout.rdbuf()),
stream(cout)
{}

// Copy constructor (not used in this example)
Debug(const Debug& rhs) : std::ostream( rhs.stream.rdbuf() ),
stream(rhs.stream) {
}

template stream << data;
return stream;
}

private:
std::ostream& stream;
};



int main() {
Debug d;
d << "This endl is ok..." << endl;

// d << endl; // Line won't compile when uncommented -- why?
}

First observation:
I see no use of making your Debug class a subclass of ostream, since you
hold a reference to a stream inside and you are using it from operator<<.

Second observation:
If you are looking inside STL code, you'll see that for manipulators, the
operator<< is overloaded. There is a different form for them. You have no
operator << defined that accepts as a right side operand a manipulator.

Catalin



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Sat Oct 23, 2004 6:26 am    Post subject: Re: endl issues for class derived from ostream Reply with quote

Matthew Walker <m.g.walker (AT) NOmassey (DOT) SPac.AMnz> wrote


Quote:
I am trying to write a debugging (or trace) class. It effectively
sits between cout (or similar) and the user. My problem is that some
uses of endl cause a compiler error.

Can anyone suggest how I might go about solving this issue?

I think you're going about it the wrong way. The obvious solution is a
filtering streambuf inserted between the ostream and its normal
streambuf. There's an example of such at my site
([url]www.gabi-soft.fr/codebase-en)[/url], in the Util/IO code.

There's also a stream wrapper at the site. The stream wrapper,
however,
is code that was rapidly written and not thoroughly tested, so there
may
also be problems with it with things like std::endl. A quick test
showed that it worked with g++ 2.95.2, but not with more recent
compilers, due to the fact that endl was a template function. Adding
an
explicit overload for:

OutputStreamWrapper const&
operator<<( OutputStreamWrapper const& dest,
std::ostream& (*manip)( std::ostream& ) )

did the trick. (Note that in my case, the << operator is a non-member
function.)

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Randy Maddox
Guest





PostPosted: Sat Oct 23, 2004 2:17 pm    Post subject: Re: endl issues for class derived from ostream Reply with quote

Matthew Walker <m.g.walker (AT) NOmassey (DOT) SPac.AMnz> wrote

Quote:
Hi,

I am trying to write a debugging (or trace) class. It effectively sits
between cout (or similar) and the user. My problem is that some uses of
endl cause a compiler error.

Can anyone suggest how I might go about solving this issue? Of even
more interest to me would be pointers to resources that cover the
iostream classes.

Thanks in advance,

Matthew Walker

********************************************

#include <iostream

using namespace std;

class Debug : public std::ostream {
public:
// Default constructor
Debug(): ostream(cout.rdbuf()),
stream(cout)
{}

// Copy constructor (not used in this example)
Debug(const Debug& rhs) : std::ostream( rhs.stream.rdbuf() ),
stream(rhs.stream) {
}

template stream << data;
return stream;
}

private:
std::ostream& stream;
};



int main() {
Debug d;
d << "This endl is ok..." << endl;

// d << endl; // Line won't compile when uncommented -- why?
}


Get the Langer and Kreft book "Standard C++ IOStreams and Locales".
It's not an easy read, but covers a lot of ground very nicely.

Your problem above is that you don't have enough operator<<()
overloads defined. You will need at least the following in addition
to what you have:

// handle std::endl, std::ends, std::flush iomanipulators
std::ostream & operator<<(std::ostream & (*fPtr) (std::ostream &));

// handle std::setbase, std::setprecision, std::setw,
std::setiosflags and
// std::resetiosflags iomanipulators
template std::ostream & operator<<(T (*fPtr)(int value));


// handle std::setfill iomanipulator
template std::ostream & operator<<(T (*fPtr)(char fillChar));

Details on implementation of these operators can be found in Langer
and Kreft, or by looking at your existing STL implementation.

Good luck. It will be a lot of fun for you I'm sure. :-)

Randy.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Tue Oct 26, 2004 4:20 am    Post subject: Re: endl issues for class derived from ostream Reply with quote

[email]rmaddox (AT) isicns (DOT) com[/email] (Randy Maddox) wrote in message
news:<8c8b368d.0410220700.49bffe59 (AT) posting (DOT) google.com>...
Quote:
Matthew Walker <m.g.walker (AT) NOmassey (DOT) SPac.AMnz> wrote in message
news:<cl7938$1th$1 (AT) lust (DOT) ihug.co.nz>...

[...]

Quote:
Your problem above is that you don't have enough operator<<()
overloads defined. You will need at least the following in addition
to what you have:

It's actually worse than that, since presumably, users may have defined
additional manipluators. In practice, for an output stream, I've not
found that many necessary. (On the other hand, most of my experience is
still with classical iostreams. And there, you don't need any
additional functions, since the streams aren't templates. Note that the
entire problem is only due to the fact that the manipulator being passed
to his operator<< is a template function.)

Quote:
// handle std::endl, std::ends, std::flush iomanipulators
std::ostream & operator<<(std::ostream & (*fPtr) (std::ostream &));

// handle std::setbase, std::setprecision, std::setw,
std::setiosflags and
// std::resetiosflags iomanipulators
template std::ostream & operator<<(T (*fPtr)(int value));

According to the standard, these manipulators work on ios_base. A
non-template class, so the manipulator functions are not templates, and
his template function works as is.

Quote:

// handle std::setfill iomanipulator
template std::ostream & operator<<(T (*fPtr)(char fillChar));

Ditto.

Quote:
Details on implementation of these operators can be found in Langer
and Kreft, or by looking at your existing STL implementation.

I think that the Langer and Kreft book dates from before the standard.
Maybe these functions were necessary for some intermediate draft
version. I've added tests for setw and endl to my test suite for my
wrapper class, and found that I did need the first overload above. But
not the others. On the other hand, I've not run the test suite on a
whole lot of compilers yet, so maybe there are some implementations
where they will be necessary.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Randy Maddox
Guest





PostPosted: Tue Oct 26, 2004 11:31 pm    Post subject: Re: endl issues for class derived from ostream Reply with quote

[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in message
news:<d6652001.0410250035.66b8a081 (AT) posting (DOT) google.com>...
Quote:
rmaddox (AT) isicns (DOT) com (Randy Maddox) wrote in message
news:<8c8b368d.0410220700.49bffe59 (AT) posting (DOT) google.com>...
Matthew Walker <m.g.walker (AT) NOmassey (DOT) SPac.AMnz> wrote in message
news:<cl7938$1th$1 (AT) lust (DOT) ihug.co.nz>...

[...]

Your problem above is that you don't have enough operator<<()
overloads defined. You will need at least the following in addition
to what you have:

It's actually worse than that, since presumably, users may have defined
additional manipluators. In practice, for an output stream, I've not
found that many necessary. (On the other hand, most of my experience is
still with classical iostreams. And there, you don't need any
additional functions, since the streams aren't templates. Note that the
entire problem is only due to the fact that the manipulator being passed
to his operator<< is a template function.)

// handle std::endl, std::ends, std::flush iomanipulators
std::ostream & operator<<(std::ostream & (*fPtr) (std::ostream &));

// handle std::setbase, std::setprecision, std::setw,
std::setiosflags and
// std::resetiosflags iomanipulators
template std::ostream & operator<<(T (*fPtr)(int value));

According to the standard, these manipulators work on ios_base. A
non-template class, so the manipulator functions are not templates, and
his template function works as is.


// handle std::setfill iomanipulator
template std::ostream & operator<<(T (*fPtr)(char fillChar));

Ditto.

Details on implementation of these operators can be found in Langer
and Kreft, or by looking at your existing STL implementation.

I think that the Langer and Kreft book dates from before the standard.
Maybe these functions were necessary for some intermediate draft
version. I've added tests for setw and endl to my test suite for my
wrapper class, and found that I did need the first overload above. But
not the others. On the other hand, I've not run the test suite on a
whole lot of compilers yet, so maybe there are some implementations
where they will be necessary.

Well, for some of these manipulators, e.g., setw, as shown below, the
return
type is implementation defined. Thus making these functions templates
in your code allows them to be different on different compilers. Is
that not correct?

Below from 27.6 of the Standard:

Header namespace std {
// Types T1, T2, ... are unspecified implementation types
T1 resetiosflags(ios_base::fmtflags mask);
T2 setiosflags (ios_base::fmtflags mask);
T3 setbase(int base);
template<charT> T4 setfill(charT c);
T5 setprecision(int n);
T6 setw(int n);
}

Thanks.

Randy.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Wed Oct 27, 2004 1:56 pm    Post subject: Re: endl issues for class derived from ostream Reply with quote

[email]rmaddox (AT) isicns (DOT) com[/email] (Randy Maddox) wrote in message
news:<8c8b368d.0410260711.77de436b (AT) posting (DOT) google.com>...
Quote:
kanze (AT) gabi-soft (DOT) fr wrote in message
news:<d6652001.0410250035.66b8a081 (AT) posting (DOT) google.com>...
[email]rmaddox (AT) isicns (DOT) com[/email] (Randy Maddox) wrote in message
news:<8c8b368d.0410220700.49bffe59 (AT) posting (DOT) google.com>...
Matthew Walker <m.g.walker (AT) NOmassey (DOT) SPac.AMnz> wrote in message
news:<cl7938$1th$1 (AT) lust (DOT) ihug.co.nz>...

[...]

// handle std::endl, std::ends, std::flush iomanipulators
std::ostream & operator<<(std::ostream & (*fPtr) (std::ostream &));

// handle std::setbase, std::setprecision, std::setw,
std::setiosflags and
// std::resetiosflags iomanipulators
template std::ostream & operator<<(T (*fPtr)(int value));

According to the standard, these manipulators work on ios_base. A
non-template class, so the manipulator functions are not templates,
and his template function works as is.


// handle std::setfill iomanipulator
template std::ostream & operator<<(T (*fPtr)(char fillChar));

Ditto.

Details on implementation of these operators can be found in
Langer and Kreft, or by looking at your existing STL
implementation.

I think that the Langer and Kreft book dates from before the
standard. Maybe these functions were necessary for some
intermediate draft version. I've added tests for setw and endl to
my test suite for my wrapper class, and found that I did need the
first overload above. But not the others. On the other hand, I've
not run the test suite on a whole lot of compilers yet, so maybe
there are some implementations where they will be necessary.

Well, for some of these manipulators, e.g., setw, as shown below, the
return type is implementation defined. Thus making these functions
templates in your code allows them to be different on different
compilers.

The issue is not whether they should be templates. The issue is whether
you need a specialization of your global template for them. In
practice, you only need the specialization if the manipulator itself is
a template (because in this case, the compiler cannot do the type
induction necessary to instantiate the general template). This is the
case for basic_istream and basic_ostream manipulators, since
basic_istream and basic_ostream are themselves templates. (Of course,
if you are only using istream and ostream, then your overload doesn't
necessarily have to be a template.)

The standard says that setbase, setprcecision, setw, setiosflags,
resetiosflags and setfill are non template functions on ios_base. Since
there is only one instance of each, the general template should work,
and there is no need for specialization

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.