Topic: iostreams extensibility questions
Author: kanze@gabi-soft.de
Date: Mon, 30 Oct 2000 18:42:38 GMT Raw View
Matthew Austern <austern@research.att.com> writes:
|> kanze@gabi-soft.de writes:
|> > One might argue that e.g. istream should in fact be two classes, a =
base
|> > class whose only contract is to deliver the requested types, and a
|> > derived class whose additional contract involves text formatting. =
If
|> > this were the case, of course, you'd also want some mechanism of
|> > preventing programmers from defining the operator>> on the base cla=
ss,
|> > when their operator>> actually depended on text streams.
|> To a large extent, of course, that's how things already look. (Excep=
t
|> that this separation of functionality is handled by another mechanism
|> than inheritance.)
|> The division isn't perfect, but you won't go too far wrong if
|> you think of it this way:
|> - streambuf classes handle buffering, and transport of=20
|> characters to and from the underlying source or destination.
|> - locale facets handle formatting.
|> - istream and ostream are wrapper classes that bind streambufs
|> to locale facets. istream and ostream are not customizable,
|> either by inheritance or any other mechanism, because all of
|> the behavior you might want to change is somewhere else.
That's part of it, of course. The other part is that if I want to
extend iostream to support formatting of my own types, I do so by
overloading operators << and >>. And I can count on the correct
formatting behavior from the existing operator<< and >>.
In modern C++, this could have been achieved by means of a template
member function, rather than operators. Whether this would have been an
improvement is debatable, and at any rate, if the member functions were
templates, they couldn't be virtual.
--=20
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: the_wid@my-deja.com (Tom)
Date: 2000/10/13 Raw View
On Fri, 13 Oct 2000 14:50:18 GMT, "Eric Gretzinger"
<gretzinger@earthlink.net> wrote:
>I understand this, but the design through automatic type promotion of short
>and int to long, and the respective unsigned quantities, makes it impossible
>to build a "reciprocal" binary read/write system that uses basic_istream and
>basic_ostream extraction/insertion operators.
The iostream insertion/extraction operators were never intended for
binary i/o. What makes you think they were? They are the C++
equivalent of printf.
If you want to do binary i/o, you'll have to pick some suitable
operators, or just do it with overloaded functions.
For example:
template<class T>
std::streambuf* binarywrite(std::streambuf* s, T const& t)
{
s->sputn(reinterpret_cast<char*>(&t), sizeof(T));
return s;
}
(add error checking, etc)
Then specialize for any non POD types.
Tom
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Stephen Howe" <SPAMGUARDstephen.howe@dial.pipex.co.uk>
Date: 2000/10/13 Raw View
Eric Gretzinger <gretzinger@earthlink.net> wrote in message
news:LZrF5.31$0d.16067@news1.epix.net...
> For a binary write, this means that two successive 4 byte quantities get
> written to the streambuf and subsequently to the file. If I then reopen
the
> file at a later time and read two shorts, the num_get facet get(short)
> function gets called. Depending on the endian-ness of the system, either
the
> first short will be zero, or the second short will be zero. The value of
the
> second written short, which resides somewhere in bytes 4-8 within the
file,
> never gets read.
Then you should be using member functions read() & write() which do binary
read's and write's respectively not extractors or inserters which give text
input/output.
Stephen Howe
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: kanze@gabi-soft.de
Date: Sun, 15 Oct 2000 03:24:50 GMT Raw View
"Eric Gretzinger" <gretzinger@earthlink.net> writes:
|> I have been attempting to design binary insertion and extraction of
|> fundamental types using the insertion and extraction operators
|> provided by basic_istream and basic_ostream.
This is a fundamental design error. Conceptually, user defined
operator<< and operator>> extend the class, much in the same way a
virtual function would. And so they must meet the same pre- and post
conditions, and can count on other operator>> and operator<< meeting
these conditions. An important pre-conditoion for operator>> and
post-condition for operator<< is that the external format is text. User
defined operator>> and operator<< may, and often do, count on this.
If you want to use a different type of formatting, you need to define a
different types of basic istream and ostream, unrelated to the existing
ones. That means, of course, that functions accepting an istream or an
ostream will not accept the new type of stream, but that is a good
thing, generally, since such functions will have been written with the
contract of istream and ostream in mind, including text IO. They might
work anyway, but then again, they might not.
One might argue that e.g. istream should in fact be two classes, a base
class whose only contract is to deliver the requested types, and a
derived class whose additional contract involves text formatting. If
this were the case, of course, you'd also want some mechanism of
preventing programmers from defining the operator>> on the base class,
when their operator>> actually depended on text streams.
|> My goal for using insertion and extraction operators as opposed to
|> unformatted read/write is so that a preponderance of code that relies
|> on I/O does not require specific stream dependencies. To this end, I
|> first looked at derivation from basic_istream and basic_ostream.
|> This doesn't work because the insertion and extraction operators are
|> not virtual functions. I also looked into changing facets and also
|> streambufs for the purpose of implementing a variety of translation
|> protocols and a variety of physical I/O sources/sinks. This also
|> cannot work because not all the insertion/extraction operators use
|> facets that are not necessarily reciprocal (specifically, num_put and
|> num_get do not implement the same set of put/get functions for
|> fundamental types). After thinking about this problem for some time,
|> I and came up with a number of questions relating to the C++ standard
|> that are perplexing me:
|> 1. Why doesn't the C++ standard define the basic_istream extraction
|> operators, and the basic_ostream insertion operators as virtual?
Because it wants to be sure that the contract is enforced.
|> 2. Why aren't extraction and insertion operators of type charT member=
s of
|> basic_istream and basic_ostream respectively?
Since they aren't virtual, it is indifferent whether they are members or
not. There is a slight advantage in their being non-members -- their
addresses are simple pointer to functions, and not pointer to member
functions. Which means that they can be used directly in certain
contexts by the standard algorithms. Offhand, I can't think of a good
example, but I can't think of a reason to forbid it either.
--=20
James Kanze mailto:kanze@gabi-soft.de
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
Ziegelh=FCttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Stephen Howe" <SPAMGUARDstephen.howe@dial.pipex.co.uk>
Date: 2000/10/12 Raw View
Eric Gretzinger <gretzinger@earthlink.net> wrote in message
news:940F5.59$s5.41243@news1.epix.net...
> 4. Why aren't the num_put and num_get facets reciprocal? The num_put facet
> provides put functions for: bool, long, unsigned long, double, and long
> double. The num_get facet provides get functions for; bool, unsigned
short,
> unsigned int, long, unsigned long, float, double, and long double.
num_put does not require put functions for unsigned short, unsigned int,
short and int as the arguments are promoted and one of long, unsigned long
is used. Similarly float is pormoted to double.
In contrast num_get requires the full built in types as you cannot overwrite
memory.
It is very similar to printf()/scanf(). printf() does not need a % specifier
to printf floats as they are promoted and passed as doubles, scanf()
requires a % specifier to map to all the built in C++ types.
Stephen Howe
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: Stephen Clamage <stephen.clamage@sun.com>
Date: 2000/10/12 Raw View
On Wed, 11 Oct 2000 16:58:18 GMT, "Eric Gretzinger"
<gretzinger@earthlink.net> wrote:
>
>1. Why doesn't the C++ standard define the basic_istream extraction
>operators, and the basic_ostream insertion operators as virtual?
Whether these functions should be virtual was the subject of debate at
different times. The design principle was that the formatting layer of
streams was not to be derived from, and that when you invoked one of
the predefined formatting functions, you knew exactly what you would
get. Other design principles are reasonable, but the original designer
of iostreams, Jerry Schwarz, felt very strongly about this point, and
won over those who suggested alternatives.
>
>2. Why aren't extraction and insertion operators of type charT members of
>basic_istream and basic_ostream respectively?
They are. The parameters are described as char_type, which is a
typedef for charT.
>
>3. Why don't the num_put and num_get facets provide put/get functions for
>all fundamental types except for the character type?
They provide functions for all the predefined numeric types and void*.
What other fundamental types would you like to see for numeric I/O?
>
>4. Why aren't the num_put and num_get facets reciprocal? The num_put facet
>provides put functions for: bool, long, unsigned long, double, and long
>double. The num_get facet provides get functions for; bool, unsigned short,
>unsigned int, long, unsigned long, float, double, and long double.
For reading, you need an exact match of the reference parameter to the
type being read. That is, for something like
T i; // T is a numeric type
get(i);
you need a get having a T& parameter.
But for writing integer values, it is sufficient to have long (and
unsigned long), since the conversions from short and int (and the
unsigned versions) are safe and well-defined.
---
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Eric Gretzinger" <gretzinger@earthlink.net>
Date: 2000/10/13 Raw View
"Stephen Howe" <SPAMGUARDstephen.howe@dial.pipex.co.uk> wrote in message
news:8s4s7r$i6r$1@soap.pipex.net...
>
> Eric Gretzinger <gretzinger@earthlink.net> wrote in message
> news:940F5.59$s5.41243@news1.epix.net...
>
> > 4. Why aren't the num_put and num_get facets reciprocal? The num_put
facet
> > provides put functions for: bool, long, unsigned long, double, and long
> > double. The num_get facet provides get functions for; bool, unsigned
> short,
> > unsigned int, long, unsigned long, float, double, and long double.
>
> num_put does not require put functions for unsigned short, unsigned int,
> short and int as the arguments are promoted and one of long, unsigned long
> is used. Similarly float is pormoted to double.
>
> In contrast num_get requires the full built in types as you cannot
overwrite
> memory.
>
> It is very similar to printf()/scanf(). printf() does not need a %
specifier
> to printf floats as they are promoted and passed as doubles, scanf()
> requires a % specifier to map to all the built in C++ types.
>
> Stephen Howe
>
I understand this, but the design through automatic type promotion of short
and int to long, and the respective unsigned quantities, makes it impossible
to build a "reciprocal" binary read/write system that uses basic_istream and
basic_ostream extraction/insertion operators. For example, if I write two
shorts to a file, the num_put facet put(long) function gets called twice.
For a binary write, this means that two successive 4 byte quantities get
written to the streambuf and subsequently to the file. If I then reopen the
file at a later time and read two shorts, the num_get facet get(short)
function gets called. Depending on the endian-ness of the system, either the
first short will be zero, or the second short will be zero. The value of the
second written short, which resides somewhere in bytes 4-8 within the file,
never gets read.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Eric Gretzinger" <gretzinger@earthlink.net>
Date: 2000/10/13 Raw View
"Stephen Clamage" <stephen.clamage@sun.com> wrote in message
news:796aus8b21emvesc7bu4ck2vfsijdeg5oo@4ax.com...
> On Wed, 11 Oct 2000 16:58:18 GMT, "Eric Gretzinger"
> <gretzinger@earthlink.net> wrote:
> >
> >1. Why doesn't the C++ standard define the basic_istream extraction
> >operators, and the basic_ostream insertion operators as virtual?
>
> Whether these functions should be virtual was the subject of debate at
> different times. The design principle was that the formatting layer of
> streams was not to be derived from, and that when you invoked one of
> the predefined formatting functions, you knew exactly what you would
> get. Other design principles are reasonable, but the original designer
> of iostreams, Jerry Schwarz, felt very strongly about this point, and
> won over those who suggested alternatives.
>
> >
> >2. Why aren't extraction and insertion operators of type charT members of
> >basic_istream and basic_ostream respectively?
>
> They are. The parameters are described as char_type, which is a
> typedef for charT.
>
The C++ standard defines inserters/extractors for type charT, char, unsigned
char, char*, and unsigned char* outside of the basic_ostream and
basic_istream classes, i.e. they are not member functions of these classes.
> >
> >3. Why don't the num_put and num_get facets provide put/get functions for
> >all fundamental types except for the character type?
>
> They provide functions for all the predefined numeric types and void*.
> What other fundamental types would you like to see for numeric I/O?
>
num_put does not define put(short), put(unsigned short), put(int), and
put(unsigned int). I understand that these types get promoted to long and
unsigned long on a put. The problem I'm having is that I'd like to read and
write binary data to a file using basic_ostream and basic_istream
insertion/extraction operators. The upshot is that if I write a short
through operator<<, my num_put subclass facet has no option but to write 4
bytes. If I then try to read in a short from the file using operator>>, my
num_get subclass will use get(short), only extracting 2 bytes.
> >
> >4. Why aren't the num_put and num_get facets reciprocal? The num_put
facet
> >provides put functions for: bool, long, unsigned long, double, and long
> >double. The num_get facet provides get functions for; bool, unsigned
short,
> >unsigned int, long, unsigned long, float, double, and long double.
>
> For reading, you need an exact match of the reference parameter to the
> type being read. That is, for something like
> T i; // T is a numeric type
> get(i);
> you need a get having a T& parameter.
>
> But for writing integer values, it is sufficient to have long (and
> unsigned long), since the conversions from short and int (and the
> unsigned versions) are safe and well-defined.
>
> ---
> Steve Clamage, stephen.clamage@sun.com
Eric Gretzinger
gretzinger@earthlink.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]
Author: "Eric Gretzinger" <gretzinger@earthlink.net>
Date: 2000/10/11 Raw View
I have been attempting to design binary insertion and extraction of
fundamental types using the insertion and extraction operators provided by
basic_istream and basic_ostream. My goal for using insertion and extraction
operators as opposed to unformatted read/write is so that a preponderance of
code that relies on I/O does not require specific stream dependencies. To
this end, I first looked at derivation from basic_istream and basic_ostream.
This doesn't work because the insertion and extraction operators are not
virtual functions. I also looked into changing facets and also streambufs
for the purpose of implementing a variety of translation protocols and a
variety of physical I/O sources/sinks. This also cannot work because not all
the insertion/extraction operators use facets that are not necessarily
reciprocal (specifically, num_put and num_get do not implement the same set
of put/get functions for fundamental types). After thinking about this
problem for some time, I and came up with a number of questions relating to
the C++ standard that are perplexing me:
1. Why doesn't the C++ standard define the basic_istream extraction
operators, and the basic_ostream insertion operators as virtual?
2. Why aren't extraction and insertion operators of type charT members of
basic_istream and basic_ostream respectively?
3. Why don't the num_put and num_get facets provide put/get functions for
all fundamental types except for the character type?
4. Why aren't the num_put and num_get facets reciprocal? The num_put facet
provides put functions for: bool, long, unsigned long, double, and long
double. The num_get facet provides get functions for; bool, unsigned short,
unsigned int, long, unsigned long, float, double, and long double.
Enlightenment would be bliss.
Eric Gretzinger
gretzinger@earthlink.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]