简体   繁体   中英

Using Boost Karma to replace std::stringstream for double to std::string Conversion

For performance improvement, I am looking to replace:

template<class T> std::string ToStringFixed(const T x, const unsigned int width = 8)
{
  std::stringstream ss;
  ss << std::setprecision(width) << std::fixed << x;
  return ss.str();
}

With an implementation from Boost Karma as our project already uses Boost and it looks to have a significant performance gain over the naive solution above.

Something like:

std::string ToString(double d)
{
  using boost::spirit::karma::double_;
  using boost::spirit::ascii::space;
  using boost::spirit::karma::generate;

  std::string s
  std::back_insert_iterator<std::string> sink(s);
  generate(sink, double_, d);
  return s;
}

Which is adopted from: http://thisthread.blogspot.com/2011/04/generating-text-with-spirit-karma.html seems to be on the right track, but it isn't clear to me how to control the precision, or if such a solution can be template-friendly for floating point types without use of type traits. (Answers using up through C++14 are acceptable.)

You can achieve what you want with the help of real_generator 's formatting policies . Since you only need to modify the precision you can derive from the default real_policies<Num> and then add the precision(Num n) member function that has the behaviour you need.

Running on WandBox

#include <iostream>
#include <string>
#include <cmath>

#include <boost/spirit/include/karma.hpp>

template <typename Num>
struct precision_policy : boost::spirit::karma::real_policies<Num>
{
    precision_policy(int prec):precision_(prec){}
    int precision(Num n) const { return precision_; }
    int precision_;
};

std::string ToStringFixedKarma(double d, const unsigned int width = 8)
{
  using boost::spirit::karma::real_generator;
  using boost::spirit::ascii::space;
  using boost::spirit::karma::generate;

  real_generator<double,precision_policy<double> > my_double_(width);

  std::string s;
  std::back_insert_iterator<std::string> sink(s);
  generate(sink, my_double_, d);
  return s;
}

int main() {
    const double pi = std::acos(-1);
    std::cout << ToStringFixedKarma(pi) << std::endl;
    std::cout << ToStringFixedKarma(pi,2) << std::endl;
    std::cout << ToStringFixedKarma(pi,4) << std::endl;
}

PS: The documentation (and inspecting the source) seems to imply that the member functions in these policies need to be static, which would make what you need impossible, but as this example shows, that is not the case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM