I have inherited a template to convert a string to a numerical value, and want to apply it to convert to boolean. I am not very experienced with the stringstream and locale classes. I do seem to be getting some odd behaviour, and I am wondering if someone could please explain it to me?
template<typename T> T convertFromString( const string& str ) const {
std::stringstream SStream( str );
T num = 0;
SStream >> num;
return num;
}
This works fine until I try the boolean conversion
string str1("1");
int val1 = convertFromString<int>(str1); // ok
string str2("true");
bool val2 = convertFromString<bool>(str2); // val2 is _false_
I spent some time tracking down the problem. I have confirmed that the locale's truename() returns "true".
The problem seems to be with the initialisation of the variable num. I can change the template to this and it works:
template<typename T> T convertFromString( const string& str ) const {
std::stringstream SStream( str );
T num; // <----------------------- Changed here
SStream >> num;
return num;
}
string str2("true");
bool val2 = convertFromString<bool>(str2); // val2 is _true_
Why does it work? I accept that initialising a bool with '0' is wrong, but why would this cause the SStream>>num
conversion to fail?
Initialising a bool with 0 will reliably set it to false, and this has no effect on the stream extraction.
What is causing your problem is that streams by default only recognize the values 0
and 1
when dealing with booleans. To have them recognize the names true
and false
, you need to tell that explicitly to the stream with the boolalpha
manipulator.
The best way to solve your problems is to specialize the template for bool:
template<> bool convertFromString<bool>( const string& str ) const {
std::stringstream SStream( str );
bool val = false;
SStream >> val;
if( SStream.fail() )
{
SStream.clear();
SStream >> boolalpha >> val;
}
return val;
}
Note that your change did not make the code work. It just appeared to do so for the single testcase you used.
With your change, the function failed to read from the stream and returned an uninitialised value. As any non-zero value will be interpreted as true, the function appears to work, but as soon as you try to extract "false"
, you will see it fail (the function still returns true).
Edit: Adapted the code to handle both numeric and alpha bools.
This is because the stringstream conversion from 'true' fails - your function template should check SStream.fail()
before it returns, so you can discover similar failures more easily.
When you init the bool its value is false. When you don't init it (after you remove the = 0), it is random garbage (usually non-zero) and returns true.
template<typename T> T convertFromString( const string& str ) {
std::stringstream SStream( str );
T num = 0;
SStream >> num;
if (SStream.fail())
{
// conversion failure - handle error
bool error = true;
}
return num;
}
来源:https://stackoverflow.com/questions/3880927/num-get-facet-and-stringstream-conversion-to-boolean-fails-with-initialised-bo