c++ - 如何使用 Boost.Spirit 在 C++ 中序列化一个 double,以便输出接近标准流的输出?

标签 c++ boost-spirit

我想替换对 boost::lexical_cast<std::string>(d) 的调用解决方案:

  1. 不使用语言环境(我怀疑这是多线程应用程序运行缓慢的原因),
  2. 保留与 lexical_cast 相同的输出.

我正在使用用 Boost.Spirit.Karma 编写的生成器(因为它更快)。但是改了之后结果不一样了,因为Karma有自己的方式来显示double的小数部分

我知道在某种程度上可以控制 double带有策略的生成器,但我的尝试失败了。我能想到的最好的办法就是这个生成器定制和这个测试程序:

#include <limits>
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/karma.hpp>

namespace karma = boost::spirit::karma;

template <typename Num>
struct fp_policy : karma::real_policies<Num>
{
  template <typename OutputIterator>
  static bool dot (OutputIterator& sink, Num n, unsigned /*precision*/)
  {
      if (n)
        return karma::char_inserter<>::call(sink, '.');  // generate the dot by default
      else
        return false;
  }

  static unsigned precision(Num)
  {
      return 15;
  }
};

karma::real_generator<double, fp_policy<double>> const fp_generator {};

std::string karma_to_string(double const& v)
{
    std::string ans;
    std::back_insert_iterator<std::string> sink {ans};
    (void)karma::generate(sink, fp_generator, v);
    return ans;
}

void test_number (double x)
{
  std::cout << "stream:        " << x << "\n";
  std::cout << "lexiical_cast: " << boost::lexical_cast<std::string>(x) << "\n";
  std::cout << "spirit:        " << karma_to_string(x) << "\n";
  std::cout << "--------------------------------------------" << std::endl;
}

int main()
{
  test_number(0.45359237);
  test_number(111.11);
  test_number(1.0);
  test_number(3.25);
}

它给出了以下输出:

stream:        0.453592
lexiical_cast: 0.45359237000000002
spirit:        0.45359237
--------------------------------------------
stream:        111.11
lexiical_cast: 111.11
spirit:        111.109999999999999
--------------------------------------------
stream:        1
lexiical_cast: 1
spirit:        1
--------------------------------------------
stream:        3.25
lexiical_cast: 3.25
spirit:        3.25
--------------------------------------------

如您所见,两者之间存在明显差异。如果我使用默认的 double 生成器 ( karma::double_ ),结果仍然会有所不同,但在不同的地方:

stream:        0.453592
lexiical_cast: 0.45359237000000002
spirit:        0.454
--------------------------------------------
stream:        111.11
lexiical_cast: 111.11
spirit:        111.11
--------------------------------------------
stream:        1
lexiical_cast: 1
spirit:        1.0
--------------------------------------------
stream:        3.25
lexiical_cast: 3.25
spirit:        3.25
--------------------------------------------

我的问题:如何为 double 配置生成器s(或者甚至可能吗?)以便输出更接近基于流的转换器?

最佳答案

我会创建一个基于 sprintf 的生成器,就像我在此处进行的逆向工程一样:

That answer comes with a full test-suite to verify "lexical-cast compliance" for values including NaN, positive/negative zero and infinities.

如果你愿意,我可以想出一个演示。到目前为止,最简单的做法似乎是将值包装在具有重载输出流操作的类型中,以便 boost::spirit::karma::stream directive可以使用。

或者,您可以创建自定义生成器类型(满足 concept requirements )。

关于c++ - 如何使用 Boost.Spirit 在 C++ 中序列化一个 double,以便输出接近标准流的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49432988/

相关文章:

c++ - 是否可以循环遍历模板参数?

c++ - 这个归并排序有问题

c++ - 是否可以使用 boost-spirit 直接解析为嵌套的 POD?

boost - 为什么在 boost Spirit 中使用流会对性能造成如此大的影响?

c++ - 频繁变化的大型数据集的最佳数据结构

c++ - Opencv 相机分辨率问题

c++ - 什么是悬空引用?

c++ - 使用 Boost::Spirit 解析转义字符串

c++ - 从排列的解析器表达式列表中动态(在运行时)生成 Spirit 解析器表达式

c++ - boost::spirit::qi 规则减少解析错误