 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Matthew Walker Guest
|
Posted: Thu Oct 21, 2004 5:27 pm Post subject: endl issues for class derived from ostream |
|
|
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
|
Posted: Fri Oct 22, 2004 5:19 pm Post subject: Re: endl issues for class derived from ostream |
|
|
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
|
Posted: Fri Oct 22, 2004 5:41 pm Post subject: Re: endl issues for class derived from ostream |
|
|
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
|
Posted: Fri Oct 22, 2004 5:42 pm Post subject: Re: endl issues for class derived from ostream |
|
|
"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
|
Posted: Fri Oct 22, 2004 5:43 pm Post subject: Re: endl issues for class derived from ostream |
|
|
"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
|
Posted: Sat Oct 23, 2004 6:26 am Post subject: Re: endl issues for class derived from ostream |
|
|
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
|
Posted: Sat Oct 23, 2004 2:17 pm Post subject: Re: endl issues for class derived from ostream |
|
|
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
|
Posted: Tue Oct 26, 2004 4:20 am Post subject: Re: endl issues for class derived from ostream |
|
|
[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
|
Posted: Tue Oct 26, 2004 11:31 pm Post subject: Re: endl issues for class derived from ostream |
|
|
[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
|
Posted: Wed Oct 27, 2004 1:56 pm Post subject: Re: endl issues for class derived from ostream |
|
|
[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 |
|
 |
|
|
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
|
|