Problem with endl in derived streams

R

ricardw

Hi!

I've tried to find an answer to this in the FAQ and elsewhere on the
net, without success. I'm fairly sure that the issue must have turned
up before and that at least a handful of people may be able to point me
in the right direction.

Ok, I was trying to debug some code where endl appearantly wasn't
doing it's job, or at least, did not seem to be inserting an '\n' into
the stream. I managed to crystalize the problem area into this snippet:


#include <ostream>
#include <iostream>
#include <fstream>

using namespace std;

#define USE_OWN_ENDL (0)

class test_stream: public ofstream
{
public:
test_stream() {}
};

template <typename T> test_stream &operator<<(test_stream &s, T t)
{
std::cout << t;
return s;
}

#if USE_OWN_ENDL
test_stream &operator<<(test_stream &s, test_stream &(*fp)(test_stream
&))
{
return (*fp)(s);
}

test_stream &endl(test_stream &s)
{
std::cout << endl;
return s;
}

#endif

int main(int argc, char **argv)
{
cout << "Directly from main:\n";
cout << "Hello world" << endl;
cout << "Hello again" << endl;

cout << "Using 'test_stream' class:\n";
test_stream new_stream;
(new_stream << "Hello world") << endl;
(new_stream << "Hello again") << endl;
}


Now, as written (USE_OWN_ENDL is 0), the program does not output any
newlines to the new_stream. If I set USE_OWN_ENDL to 1, my own endl
function is invoked via the overloaded operator<<(test_stream&,
test_stream& (*fp)(test_stream&) call and it all works nicely. While
this is definitely possible, my guts are telling me there's a more
elegant way.

My feeling is that what is going on here is that since I've created my
own stream class, the base class operator<< does not come into play for
manipulators such as endl. Is it possible to define a suitable
operator<< that does this, so that I don't have to define my own endl?
I've tried various approaches that don't compile properly. Or is there
another approach to get this to work?

A related question: is this something that has changed in later years
because of a change in the standards or something? It seems to me that
the code I'm trying to work with must have worked (i.e. endls used as
described would have output '\n') at some time in some environment, and
it is only a couple of years old. So has endl worked in the way
expected because of a broken compiler or header file implementation at
some point?

Using g++ 3.3.5 (on Linux 2.6.8)

[Disclaimer: yes I know '\n' might be prefereble to endl, yes the
test_stream class doesn't do anything useful as it is written; I've
removed everything that's not related to the problem, the real class
adds some (slight) functionality to the stream]

/Ricard
 
K

Karl Heinz Buchegger

My feeling is that what is going on here is that since I've created my
own stream class, the base class operator<< does not come into play for
manipulators such as endl. Is it possible to define a suitable
operator<< that does this, so that I don't have to define my own endl?
I've tried various approaches that don't compile properly. Or is there
another approach to get this to work?

I can't answer your question.
But: The real question should be: Why do you want to derive
a new class from ofstream.
Usually that results in a lot of problems and is not necessary.
 
J

John Carson

Hi!

I've tried to find an answer to this in the FAQ and elsewhere on the
net, without success. I'm fairly sure that the issue must have turned
up before and that at least a handful of people may be able to point
me in the right direction.

Ok, I was trying to debug some code where endl appearantly wasn't
doing it's job, or at least, did not seem to be inserting an '\n' into
the stream. I managed to crystalize the problem area into this
snippet:


#include <ostream>
#include <iostream>
#include <fstream>

using namespace std;

#define USE_OWN_ENDL (0)

class test_stream: public ofstream
{
public:
test_stream() {}
};

template <typename T> test_stream &operator<<(test_stream &s, T t)
{
std::cout << t;
return s;
}

#if USE_OWN_ENDL
test_stream &operator<<(test_stream &s, test_stream &(*fp)(test_stream
&))
{
return (*fp)(s);
}

test_stream &endl(test_stream &s)
{
std::cout << endl;
return s;
}

#endif

int main(int argc, char **argv)
{
cout << "Directly from main:\n";
cout << "Hello world" << endl;
cout << "Hello again" << endl;

cout << "Using 'test_stream' class:\n";
test_stream new_stream;
(new_stream << "Hello world") << endl;
(new_stream << "Hello again") << endl;
}


Now, as written (USE_OWN_ENDL is 0), the program does not output any
newlines to the new_stream. If I set USE_OWN_ENDL to 1, my own endl
function is invoked via the overloaded operator<<(test_stream&,
test_stream& (*fp)(test_stream&) call and it all works nicely. While
this is definitely possible, my guts are telling me there's a more
elegant way.

My feeling is that what is going on here is that since I've created my
own stream class, the base class operator<< does not come into play
for manipulators such as endl. Is it possible to define a suitable
operator<< that does this, so that I don't have to define my own endl?
I've tried various approaches that don't compile properly. Or is
there another approach to get this to work?

Based on my reading of Josuttis (The C++ Standard Library, pp. 612ff), it
seems that there is an overloaded operator<< for ostream that handles endl
and other manipulators. To get your code to work as you wish, it seems that
you simply need to modify your overload so it picks up the stream
manipulators that are already defined. This means that the function pointer
needs to be in terms of ostream, not test_stream.

The following works on your code, but robustness is not guaranteed.

test_stream &operator<<(test_stream &s, ostream &(*fp)(ostream &))
{
(*fp)(cout);
return s;
}
 
R

ricardw

Thanks John, that does fix the problem. Looking at it, it's almost too
obvious.

As for why the original stream class is derived from ofstream, well I
don't honestly know,
I'm just trying to get the code running again with as little effort as
possible (aren't we all :) .

/Ricard
 
D

Dietmar Kuehl

I've tried to find an answer to this in the FAQ and elsewhere on the
net, without success.

Exactly this question was discussed many times in this forum and
in comp.lang.c++.moderated. Searching e.g. for "endl derived stream"
on said:
template <typename T> test_stream &operator<<(test_stream &s, T t)
{
std::cout << t;
return s;
}

This code is your problem: you *shall not* derive from 'std::eek:stream'
or its derived classes to change the output behavior! The *only*
reason to derive from 'std::eek:stream' is to create a convenience
interface for creating an 'std::eek:stream' with a derive stream buffer.
If you want to change the approach of output for a stream you shall
derive from 'std::streambuf'. Likewise for 'std::istream' and input.

More details and reasoning for this can easily be found by searching
past articles from me and/or James Kanze on the topic of stream
buffers.
 

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,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top