Re: insertion, extraction, and streams
* Christopher:
I tryed an example of how to do streams "the right way" based on an
example from the book "Standard C++ IOStreams and Locals" by Langer and
Kreft. My example doesn't seem to handle errors correctly. I am unsure
if the problem is arising from the << and >> operators for my user
defined type, or the handling of std::cin itself.
The statement below is difficult for me to understand:
If I uncomment the
ignore statement, std::cin::operator >> never seems to return. Otherwise
it just goes into an infinite loop.
"never seems to return" is to my mind about the same as "goes into an
infinite loop", yet, from the word "Otherwise", these two possibilities
seem to be regarded as mutually exclusive alternatives?
Any advise?
[snip]
// Reset error bits
std::cin.clear();
/* Infinite loop detectable here */
/* If I uncomment this then the getting of input never stops when
enter is hit
*
// Empty any left over characters from the stream
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
*/
Make that
std::cin.ignore( INT_MAX, '\n');
Otherwise is ignoring until end-of-file (in Windows, until you type Ctrl
Z on an empty line, or with redirected input, until end-of-file).
Be aware though, that when I made this change, your current program
simply ignored end-of-file, and kept asking for a valid date until one
was entered. That's surely not the behavior you want.
Cheers, & hth.,
- Alf
PS: Keeping the 'main' function as-is, the earlier stuff might be recoded as
#include <ctime>
#include <locale>
#include <limits>
#include <iostream>
//--------------------------------------------------------------------------
// A very simplified date class:
class Date
{
private:
std::tm myComponents;
public:
Date(int day, int month, int year)
{
myComponents.tm_mday = day;
myComponents.tm_mon = month - 1;
myComponents.tm_year = year - 1900;
}
Date( std::tm const& components )
: myComponents( components )
{}
std::tm components() const { return myComponents; }
};
//--------------------------------------------------------------------------
// The insertion and extraction methods for the Date class
template<class CharT, class Traits>
std::basic_istream<CharT, Traits> & operator>>(
std::basic_istream<CharT, Traits>& stream,
Date& date
)
{
typedef std::istreambuf_iterator<CharT, Traits> InputIterator;
typedef std::time_get<CharT, InputIterator > TimeFacet;
if( !stream.good() ) { return stream; }
TimeFacet const& timeFacet =
std::use_facet<TimeFacet>( stream.getloc() );
std::tm dateComponents;
std::ios_base::iostate state = std::ios_base::goodbit;
timeFacet.get_date(
stream,
InputIterator(),
stream,
state,
&dateComponents
);
stream.setstate( state );
if( stream.good() ) { date = Date( dateComponents ); }
return stream;
}
template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>& operator<<(
std::basic_ostream<CharT, Traits>& stream,
Date const& date
)
{
typedef std::ostreambuf_iterator<CharT, Traits> OutputIterator;
typedef std::time_put<CharT, OutputIterator > TimeFacet;
if( !stream.good() ) { return stream; }
TimeFacet const& timeFacet =
std::use_facet<TimeFacet>( stream.getloc() );
std::tm const dateComponents = date.components();
if( timeFacet.put( stream, stream, stream.fill(), &dateComponents,
'x' ).failed() )
{
stream.setstate( std::ios_base::badbit );
}
return stream;
}
Since I hate iostreams I don't know how correct that is: I simply
transformed your code in order to remove Date's direct dependency on
iostreams, and to name things.
However, when striving for correctness, as seems to be your goal, it's
generally a good idea to decouple things and to name things, for clarity.
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?