We would like to store the date format string in the iostream storage through std::ios_base::iword() and std::ios_base::pword(). In this way, the input and output operations for date objects can access the format string for parsing and formatting. Format parameters are often set with manipulators (see Section 28.3.2), so we should add a manipulator that sets the date format string. It could be used like this:
date today;
std::ofstream ostr;
// ...
ostr << setfmt("%D") << today;
Here is a suggested implementation for such a manipulator (note that the name of the base class is implementation-defined):
class setfmt : public smanip<const char*>
{
public:
setfmt(const char* fmt)
: smanip<const char*>(setfmt_,fmt) {}
private:
static const int datfmtIdx; //1
static std::ios_base& setfmt_(std::ios_base& str,
const char* fmt)
{
str.pword(datfmtIdx) = const_cast<char*> (fmt); //2
return str;
}
template<class charT, class Traits>
friend std::basic_ostream<charT, Traits>& //3
operator<<(basic_ostream<charT, Traits>& os,
const date& dat);
};
const int setfmt::datfmtIdx = std::ios_base::xalloc(); //4
The technique applied to implement the manipulator is described in detail in Example 2 of Section 33.3, so we won't repeat it here. But regarding this manipulator and the private use of iostream storage, there are other interesting details:
The inserter for date objects given below is almost identical to the one we described in Section 32.5.1:
template<class charT, class Traits>
std::basic_ostream<charT, Traits> &
operator << (std::basic_ostream<charT, Traits >& os,
const date& dat)
{
std::ios_base::iostate err = 0;
charT* fmt = 0;
try {
typename std::basic_ostream<charT, Traits>::sentry opfx(os);
if(opfx)
{
char* patt = static_cast<char*>
(os.pword(setfmt.datfmtIdx); //1
std::size_t len = std::strlen(patt);
fmt = new charT[len];
std::use_facet<std::ctype<charT> >(os.getloc()).
widen(patt, patt+len, fmt);
if (std::use_facet<std::time_put<charT,
std::ostreambuf_iterator<charT,Traits> > >
(os.getloc())
.put(os,os,os.fill(),&dat.tm_date,fmt,fmt+len) //2
.failed()
)
err = std::ios_base::badbit;
os.width(0);
}
}
catch(...)
{
delete [] fmt;
bool flag = false;
try {
os.setstate(std::ios_base::failbit);
}
catch(std::ios_base::failure) {
flag = true;
}
if (flag)
throw;
}
delete [] fmt;
if ( err )
os.setstate(err);
return os;
}
The only change from the previous inserter is that the format string here is read from the iostream storage (in statement //1) instead of being the fixed string "%x". The format string is then provided to the locale's time formatting facet (in statement //2).