I have this simple function that, given a string str
, if it is a number then return 'true' and overwrite the reference input num
.
template <typename T>
bool toNumber(string str, T& num)
{
bool bRet = false;
if(str.length() > 0U)
{
if (str == "0")
{
num = static_cast<T>(0);
bRet = true;
}
else
{
std::stringstream ss;
ss << str;
ss >> num; // if str is not a number op>> it will assign 0 to num
if (num == static_cast<T>(0))
{
bRet = false;
}
else
{
bRet = true;
}
}
}
else
{
bRet = false;
}
return bRet;
}
So I expect that:
int x, y;
toNumber("90", x); // return true and x is 90
toNumber("New York", y); // return false and let y unasigned.
On my machine, both debug and release configurations works fine, but on the server, only with the debug configuration, in calls like toNumber("New York", y)
the 'ss >> num' fails to recognize that str
is a string.
I checked the project configuration, but they are the same for both machines (the server is a svn-checkout of my local vs-2015 project).
I have literally no idea on how to solve the problem. Can anyone help me with this?
CodePudding user response:
Checking the value of the number that operator>>
outputs is the wrong way to go. You should check the stringstream
's failure state instead, eg:
template <typename T>
bool toNumber(string str, T& num)
{
bool bRet = false;
if (str.length() > 0U)
{
if (str == "0")
{
num = static_cast<T>(0);
bRet = true;
}
else
{
std::stringstream ss;
ss << str;
if (ss >> num) // <--
{
bRet = true;
}
else
{
bRet = false;
}
}
}
else
{
bRet = false;
}
return bRet;
}
operator>>
returns a reference to the input stream, and the stream is implicitly convertible to bool
in boolean contexts, like an if
statement, where true
means the stream is in a good state, and false
means the stream is in a failed state.
In which case, you can greatly simplify the function much much further, by getting rid of the redundant bRet
assignments, and the redundant input checks that the stringstream
will already handle for you, eg:
template <typename T>
bool toNumber(const string &str, T& num)
{
std::istringstream ss(str);
return static_cast<bool>(ss >> num);
// or:
// return !!(ss >> num);
}
CodePudding user response:
Your code is made too complicated, you can simplify it to this:
template <typename T>
bool toNumber(std::string str, T& num)
{
return !!(std::istringstream { std::move(str) } >> num);
}
https://godbolt.org/z/Pq5xGdof5
Ok I've missed that you wish to avoid zero assignment in case of failure (what streams do by default):
template <typename T>
bool toNumber(std::string str, T& num)
{
T tmp;
std::istringstream stream{ std::move(str) };
if (stream >> tmp) {
num = tmp;
}
return !!stream;
}
https://godbolt.org/z/nErqn3YYG
CodePudding user response:
if (num == static_cast<T>(0))
Bad idea. To know if operator>>
failed, check the status of the stream.
if (ss >> num) { ...
Once you have this check in place, the (totally incorrect) piece
if (str == "0")
{
num = static_cast<T>(0);
bRet = true;
}
becomes redundant, and
if(str.length() > 0U)
also becomes redundant, and then the whole thing simplifies to a line or two.