我想知道现代 C++ 中最推荐哪种方式将字符串转换为数字。双精度型、浮点型或整数型。
我遇到了 C++11
stof
,但我一直在 stringstream
中使用提取器运算符,而不是在我创建的辅助函数中使用。
然而,现在 C++11 stof
/stoi
/stod
存在。因此,我应该停止使用我的辅助函数吗?我尝试过研究这两种方法的差异,但我无法清楚地看到它们的优缺点。
template <typename T>
bool stringToValue(const std::string& item, T& value)
{
T tmp;
std::istringstream iss(item);
if ((iss >> std::dec >> tmp).fail())
{
return false;
}
else
{
value = tmp;
return true;
}
}
我也有兴趣保持尽可能高的精度。
补充一下,我在这里找到了所有可能的选项: https://www.techiedelight.com/convert-a-string-to-a-float-in-cpp/
它们不是在效率或精度方面进行比较。
注意: 我见过
std::from_chars
在 C++17 和 gcc 11 中使用(我相信)。我们(我和我的团队)最近转向了 C++17,但是,我们仍停留在 gcc 9.4.0。因此,遗憾的是我们不能使用那个。
C++中有很多解析数字的方法。要进行全面比较,请参阅此答案。
简而言之,所有函数都应该提供相同的精度。 有可能它们在某些时候都使用相同的底层例程来解析浮点数。
主要区别在于它们提供的接口,以及该接口有哪些便利/开销。像
std::atoi
这样的一些函数具有糟糕的错误处理和晦涩的名称,但由于不使用区域设置功能,并且不使用任何动态多态性,因此应该比流更有效。
如有疑问,请进行基准比较。
std::sto*
单独使用
std::sto*
系列函数是完全可以的,但它们并不能成为项目中随处使用的良好“基本实用程序”。它们在失败时抛出异常,并且在您不确定输入是否是数字(即可能失败)的情况下“尝试解析”会很慢,因为异常处理的成本非常高。
如果你不在乎并且只需要一些简单和安全的东西(尽管不是通用的),
std::sto*
功能就可以了。
std::istringstream
流开销较高,标头
<sstream>
也比较大。乍一看它们确实没有吸引力,但如果您的目标是创建“通用解析函数”,那么流比任何其他方法都更容易,因为 >>
应该适用于所有情况。
您可以继续使用当前的功能。
但是,如果包含
<sstream>
的成本太高,或者您无法承受流所具有的运行时开销,那么您必须退回到下一个最好的东西,std::strto*
函数系列:
bool stringToValue(const std::string& str, long& out, int base = 10) {
errno = 0;
char* end = nullptr;
out = std::strtol(str.data(), str.data() + str.size(), &end, base);
return str.data() != end && errno == 0;
}
bool stringToValue(const std::string& str, int& out, int base = 10) {
errno = 0;
char* end = nullptr; // note: there is no std::strtoi, so we use std::strtol
out = std::strtol(str.data(), str.data() + str.size(), &end, base);
return str.data() != end && errno == 0;
}
bool stringToValue(const std::string& str, float& out) {
errno = 0;
char* end = nullptr;
out = std::strtof(str.data(), str.data() + str.size(), &end, base);
return str.data() != end && errno == 0;
}
// ...
使用模板,我们可以避免为每种算术类型复制和粘贴实现。然而,替换流仍然需要付出很大的努力。