I'm creating a primitive type wrapper, which can use boost::lexical_cast for setting its value from a string. It works fine, but for some reason std::istream extraction operator sets the failbit. The following program prints:
123.45
EXCEPTION: ios_base::failbit setBut if you comment out the line "inStream.exceptions( ..." it works and prints:
123.45
123.45It doesn't ma开发者_C百科ke a difference if you compile with unicode or not, or if you use int or float as ValueType, the failbit gets set in any case.
#include <conio.h>
#include <exception>
#include <iostream>
#include <string>
#include <tchar.h>
#include <boost/lexical_cast.hpp>
#if defined(UNICODE) || defined(_UNICODE)
typedef std::wstring StringType;
typedef std::wistream IStreamType;
#else
typedef std::string StringType;
typedef std::istream IStreamType;
#endif
#if 1 // Use float
typedef float ValueType;
#define VALUE_STRING _T("123.45")
#else // Use int
typedef int ValueType;
#define VALUE_STRING _T("123")
#endif
struct Castable {
ValueType m_val;
};
inline IStreamType& operator>> ( IStreamType& inStream, Castable& castable )
{
inStream.exceptions( IStreamType::failbit | IStreamType::badbit );
inStream >> castable.m_val;
return inStream;
}
int _tmain(int argc, _TCHAR* argv[])
{
try{
StringType sVal = VALUE_STRING;
ValueType val;
val = boost::lexical_cast<ValueType>(sVal);
std::cout << val << std::endl;
Castable cst;
cst = boost::lexical_cast<Castable>(sVal);
std::cout << cst.m_val << std::endl;
}catch( std::exception& ex ){
std::cout << "EXCEPTION: " << ex.what() << std::endl;
}
_getch();
return 0;
}
Why would std::istream think something has gone wrong?
One reason for this might be that the implementation of lexical_cast
might deliberately try to cause some stream to fail in order to check that all of the input text was consumed. For example, a naive implementation might look like this:
template <typename Target>
Target lexical_cast(const string& s) {
/* Insert the string into a stringstream to use extraction. */
std::stringstream converter(s);
/* Pull out an object of type Target, failing if we can't. */
Target result;
if (!(converter >> result)) throw bad_lexical_cast();
/* To confirm that we read everything out of the stream, try pulling out a
* single character. If we can do this, then there is something left in the
* stream that wasn't picked up earlier and the input was malformed.
*/
char ch;
if (converter >> ch) throw bad_lexical_cast();
return result;
}
The idea here is that the final check tries to break the stream to see if something was left over. If you enable exceptions, this will turn something that should have been a normal stream failure detectable with failbit
into an exception, which is something the code didn't expect.
More generally, though, you shouldn't be setting stream settings inside of an extraction routine. That's up to the caller to do. Otherwise, no matter what you try to do with your stream before calling the extraction routine, the routine will override your preferences. It would be bad, after all, if I explicitly disabled exceptions and then had exceptions happen anyway because you turned them back on inside operator >>
.
Hope this helps!
精彩评论