什么阻碍了std::to_chars和std::from_chars的实现?

19
根据https://en.cppreference.com/w/cpp/compiler_support/17,目前尚无主要供应商支持浮点版本的std::to_charsstd::from_chars。我理解正确地格式化浮点数是非常复杂的,但是C库中存在实现。然而,这些实现受环境影响,这也是将std::to_charsstd::from_chars添加到标准中的原因之一。如果您重构C库以依赖于执行实际转换基本转换为某种中间格式的常见低级例程,那么这些函数的实现是否可以简单地免费提供?然后std::to_charsstd::from_chars可以直接或间接地使用结果,并且C和C++中的更高级API(printfatofstrtodstd::stofstd::to_string)可以执行一些更高级的操作。

8
STL 今年将在 CppCon 上发表演讲,其中一部分内容涉及到这实际上是多么困难的事情:https://cppcon2019.sched.com/event/Sft8 - Barry
VC++支持它,并且已经支持了一年左右。 - Nicol Bolas
如果您将C库重构为依赖于通用的低级例程,以执行实际的基础转换到某些中间格式,那么这些函数的实现不就会免费提供吗?据我所知,这些函数的提议是为了摆脱过去的做法,转向更高效、更轻量级的转换工具。 - NathanOliver
2个回答

16
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实现。


1
根据cppreference的说法:“只有当两个函数来自同一实现时,才能保证std::from_chars可以精确地恢复由to_chars格式化的每个浮点值。”因此,至少一个实现只需要能够与自身进行往返转换。 - Jesper Juhl
@NicolBolas 嗯,这很有趣。实现的存在不是C++特性进入的主要要求之一吗?也许措辞应该是“鼓励实现者使这些函数往返旅行”适用于C++17,然后计划将措辞更改为C++23。对于我的目的,摆脱区域设置问题并指定正确的数字位数就足够了。 - user877329
“@user877329:实现的存在不是C++中一个特性被纳入的主要要求之一吗?”你说得好像没有人正确地实现它一样。但事实上,正如之前指出的那样,他们已经实现了。此外,提案必须是可实现的,而这些往返保证非常可行。通常需要在批准之前对高度复杂的提案进行实现,但这并不特别复杂。编码难,是的,但是可以做到。 - Nicol Bolas
@NicolBolas “你这么说好像没有人正确地实现它。” 但是你说C和C++中的现有函数不能正确地执行它,所以你必须在其他地方寻找该实现。 - user877329
1
@user877329:我这么说是因为你说“如果你重构C库以依赖于通用的低级例程,这些例程可以将实际转换基础转换为某种中间格式”,但由于这些保证,这是不可能的。这个事实并不意味着没有人实现这些函数,只是没有在“C库”或其他地方实现。 - Nicol Bolas

-1

这是半答案,半问题:

我找到了一个关于该主题的讨论线程,提到了要求

字符串表示由最少数量的字符组成,以便在小数点之前(如果存在)至少有一个数字,并使用相应的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);

应该可以工作。我在这里正确吗?


4
“我正确吗?” …这不是你应该自己回答的吗?“添加回答”按钮用于回答,而不是问题。请证明它确实可以往返,并说明它与输入函数的往返将是什么。还要展示如何实现其他可能的格式化参数。 - Nicol Bolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接