【问题标题】:What blocks implementation of std::to_chars and std::from_chars什么阻止了 std::to_chars 和 std::from_chars 的实现
【发布时间】:2021-06-08 17:36:09
【问题描述】:

根据https://en.cppreference.com/w/cpp/compiler_support#cpp17,目前还没有主要供应商支持std::to_charsstd::from_chars 的浮点版本。我知道正确格式化浮点数并非易事,但 C 库中存在实现。但是这些都受到环境的影响,这也是标准中增加std::to_charsstd::from_chars的原因之一。如果您将 C 库重构为依赖于将实际转换基本转换为某种中间格式的常见低级例程,那么这些函数的实现不会简单地免费提供。然后std::to_charsstd::from_chars 可以或多或少直接使用结果,以及C 和C++ 中更高级的API:s (printf, atof, strtod, std::stof, std::to_string ) 可以做一些更花哨的事情。

【问题讨论】:

  • STL 实际上将在今年的 CppCon 上发表演讲(部分)这最终会变得多么困难:cppcon2019.sched.com/event/Sft8
  • VC++ supports it,并且已经这样做了一年左右..
  • 如果您将 C 库重构为依赖于将实际转换基本转换为某种中间格式的常见低级例程,那么这些函数的实现不会简单地免费提供。 AFAIK 提出这些功能是为了摆脱我们过去的做法,转向更高效、更轻量级的转换实用程序。

标签: c++ c++17 floating-point-conversion


【解决方案1】:

to/from_chars 功能要求实现提供往返保证(与它们自己一起)。具体来说,必须满足以下条件:

float f = //get some float
char chars[LOTS_OF_CHARS];
auto result = to_chars(chars, chars + sizeof(chars), f);
float g;
from_chars(chars, result.ptr, g);
assert(f == g);

这种保证实际上很难实现,标准库 C 或 C++ 浮点到字符串到浮点函数都没有曾经提供这种保证。所以你不能只从printf/scanfstof/to_string 获取代码,去掉语言环境的东西,然后称之为to/from_chars 实现。

【讨论】:

  • “要求所有实现都提供往返保证” - 根据cppreference:“只有当两者都提供 std::from_chars 可以准确恢复由 to_chars 格式化的每个浮点值的保证时功能来自相同的实现。”。因此,至少一个实现只需要能够与自身往返。
  • @NicolBolas 嗯,这很有趣。实现功能的存在不是进入 C++ 的主要要求之一吗?也许措辞应该是 C++17 的“鼓励实现者使这些函数往返”,然后计划将该措辞更改为 C++23。就我的目的而言,摆脱语言环境的内容并指定正确的位数就足够了。
  • @user877329:“实现功能的存在难道不是进入 C++ 的主要要求之一吗?” 你这么说好像没有人正确实现它。如前所述,他们拥有。此外,提案必须是可实施的,这些往返保证非常重要。高度复杂的提案通常需要在批准之前进行实施,但这并不是特别复杂。是的,这很难编码,但它是可行的。
  • @NicolBolas “你这么说好像没有人正确地实现它。”但是您说 C 和 C++ 中的现有函数不能正确执行,因此您必须在其他地方查找该实现。
  • @user877329:我这么说是因为你说“如果你重构 C 库以依赖于将实际转换基本转换为某种中间格式的常见低级例程”,这是不可能的由于这些保证而完成。这个事实并不意味着 没有人 实现了这些功能,只是没有在“C 库”或任何地方实现。
【解决方案2】:

这是一半的答案,一半的问题:

我找到了一个关于提到需求的主题的讨论帖

字符串表示由最小个 基数前至少有一位数字的字符 点(如果存在)并使用 对应的 std::from_chars 函数准确恢复值

但 C 库不支持。但是,如果措辞是至少正确往返所需的字符数,那么我猜

std::lock_guard l{local_mutex};
auto loc = setlocale(LC_ALL, nullptr);
setlocale(LC_ALL, "C");
char buffer[24]{};
sprintf(buffer, "%.17g", val);  // change to 9 for float
setlocale(LC_ALL, loc);

应该可以。我说的对吗?

【讨论】:

  • "我说得对吗?" ...这不是您应该自己回答的问题吗? “添加答案”按钮用于答案,而不是问题。证明这实际上是往返的,并说明它往返的输入函数是什么。同时展示你将如何实现其他可能的格式化参数。
猜你喜欢
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 2017-10-27
  • 2017-07-25
  • 1970-01-01
相关资源
最近更新 更多