Boost logo

Boost Users :

Subject: Re: [Boost-users] Why is boost::format::operator% not declared const?
From: Anthony Foiani (tkil_at_[hidden])
Date: 2013-01-17 02:49:32


Chris, greetings --

Chris Stankevitz <chrisstankevitz_at_[hidden]> writes:

> Question 1: Is there an efficient way to do the following (and by
> "more efficient" I mean fewer format constructors and string parsing):
>
> void WriteLog(float x, float y, float z, const Employee& e)
> {
> std::cout
> << "Values: "
> << boost::format("%0.3") % x
> << e
> << boost::format("%0.3") % y
> << boost::format("%0.3") % z;
> }

Please take a look at the benchmarks mentioned in the boost.format
documentation:

  http://www.boost.org/doc/libs/1_52_0/libs/format/doc/format.html#performance

They're a few years out of date, but they cover the most straight-
forward way to get the power of boost.format without quite as much
parsing / constructing overhead: make one const instance, then copy
construct to create your mutable instances.

Assuming the copy constructor is thread-safe (which, if you're not
using internal state like str() does, then it should be -- but no
guarantees...) then something like this:

  // single copy to do work of parsing
  static const boost::format fixed3proto( "%0.3f" );

  // now clone it for each format operation
  boost::format fixed3( fixed3proto );

  // and use the cloned copy
  fixed3 % x;
  return fixed3.str();

In this situation, where you have three floats that you want formatted
a particular way, then using maniuplators on cout is reasonable; just
make sure you save the state (with ios_base_all_saver or friend).

But be aware that some of those manipulators will still be in force
when you try to emit the Employee object...

> Question 2: Is there a more efficient way to do this:
>
> std::string FloatToString(float x, int DigitsAfterDecimal)
> {
> std::ostringstream FormatStream;
> FormatStream << "%0." << DigitsAfterDecimal;
> boost::format Formatter(FormatStream.str());
> Formatter % x;
> return Formatter.str();
> }

In this particular case, since you're already building an
ostringstream, you can just use the standard manipulators:

  std::ostringstream oss;
  oss << std::fixed << std::setprecision( DigitsAfterDecimal ) << x;
  return oss.str();

Note that ostringstream construction isn't entirely lightweight; if
you have an easy way of keeping an instance around in a thread-safe
manner, then you might be better off having a single instance per
thread, then doing:

  oss.str( "" );
  oss << std::fixed << std::setprecision( DigitsAfterDecimal ) << x;
  return oss.str();

(Further, if that's the only thing you ever use that ostringstream
for, you can possibly shave a few more cycles off by using the flags
field directly; I don't recall if fixed and setprecision last past a
single value output.)

However, if you really do require the fastest formatting, you're
probably best off calling into the old C library with snprintf -- but
you are then responsible for sizing your buffer correctly, etc.

Happy hacking,
t.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net