I was wondering which way is the most recommended one in modern C++ to convert a string to a number. Either double, float or integer.
I came across the C++11 stof but I have been using the extractor operator in stringstream instead within a helper function I created.
However, now with C++11 stof/stoi/stod exist. Therefor, should I stop using my helper function? I have tried researching the difference of both methods, but I cannot clearly see the pros and cons of them.
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;
}
}
I am also interested in keeping as much precision as possible.
Just to add, I found all the possible options here: https://www.techiedelight.com/convert-a-string-to-a-float-in-cpp/
They are not compared in terms of efficiency or precision.
NOTE: I have seen std::from_chars used in C++17 with gcc 11 (I believe). We (My team and I) have recently moved to C++17, However, we are stuck at gcc 9.4.0. Therefor, we cannot use that one, sadly.
There are many methods of parsing numbers in C++. For a comprehensive comparison, see this answer.
In short, all the functions should offer the same degree of precision. Chances are that they all use the same underlying routine for parsing floating point numbers at some point.
The main difference is the interface they provide, and what convenience/overhead that interface has. Some functions like std::atoi have terrible error handling and obscure names, but should be more efficient than streams due to not using locale features, and not using any dynamic polymorphism.
When in doubt, benchmark to compare their performance. There is no single function that is strictly better than all the others.
std::sto*It's perfectly fine to use std::sto* family functions on their own, but they don't make for a good "fundamental utility" that is used everywhere in the project. They throw exceptions on failure, and "attempted parsing" where you're not sure whether the input is a number (i.e. failure is likely) would be slow because exception handling is very costly.
If you don't care and you just need something simple and safe (although not generic), std::sto* functions are fine.
std::istringstreamStreams have high overhead and the header <sstream> is relatively large. They are really unattractive at first glance, but if your goal is to make a "universal parsing function", then streams make this easier than any other method because >> is supposed to work for everything.
You could keep using your current function.
However, if the include of <sstream> is too expensive, or you can't afford the run-time overhead that streams have, then you have to fall back onto the next best thing, the std::strto* family of functions:
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;
}
// ...
With templates, we could avoid copying and pasting an implementation for every single arithmetic type. However, it's still going to take a lot of effort to replace streams.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With