gcc 4.4.4: std::time_put facet instantiation, and locale imbue-ing

Kalle Olavi Niemitalo kon@iki.fi
Thu Jun 10 03:12:00 GMT 2010


Sam Varshavchik <mrsam@courier-mta.com> writes:

> I don't understand the logic I'm seeing with libstdc++'s instantiation
> of the time_put facet from a locale, and then using the facet to
> format a date into an ostream. It appears that time_put's locale gets
> ignored. The locale that's imbued in the ostream governs formatting of
> date/time localized strings.

I don't have the C++ standard at hand but Josuttis says in "The
C++ Standard Library" (1999) that std::time_put::put can access
other locale facets via its ios_base parameter.  That is what
happens with libstdc++: in <bits/locale_facets_nonio.tcc>, put
and do_put access the non-standard std::__timepunct facet of the
locale imbued in the ios_base, and call that to do the actual
formatting.  When you extract just the std::time_put facet of the
fr_FR.utf-8 locale and tell that to use an ios_base imbued with
the C locale, std::time_put::put then finds the std::__timepunct
facet of the C locale, and the output is not in French.

I suppose the standard permits this behaviour.  It does seem
inconvenient though if you want to construct a locale by mixing
and matching facets from different locales, because you cannot
know in advance which non-standard facets e.g. std::time_put will
need in each implementation of the standard C++ library.

However, if you only want to use a specific locale for a few
output operations, then I think the best option is to construct
a separate std::ios object, just for imbuing it with the desired
locale and then passing it to time_put:

  std::ios format(std::cout.rdbuf());
  format.copyfmt(std::cout);
  format.imbue(l);

  t.put(std::ostreambuf_iterator<char>(std::cout), format, ' ', &tmbuf,
        fmt, fmt+strlen(fmt));

This could even work with a NULL streambuf pointer instead of
std::cout.rdbuf(), but then the copyfmt call would throw if the
exception mask of std::cout includes std::ios_base::badbit,
so you might have to remove the copyfmt call too.  Because
std::time_put may read some of the format settings that copyfmt
copies, I think it's safer to keep it in, unless you know that
the default settings are right.

An alternative would be to imbue the output stream as you did in
your sample code, save the original locale returned from the
imbue call, and restore that later.  However, that would need
extra code for exception safety.  (Thread safety you won't get
from std::streambuf in any case, I think.)



More information about the Gcc-help mailing list