我正在创建一个原始类型的包装器,它可以使用boost :: lexical_cast从字符串设置其值。它运行正常,但由于某种原因,std :: istream提取运算符设置了failbit。打印以下程序:
123.45
EXCEPTION:ios_base :: failbit set
但是如果你注释掉“inStream.exceptions(...”这一行,那就行了并打印出来:
123.45
123.45
如果使用unicode进行编译没有区别,或者使用int或float作为ValueType,则在任何情况下都会设置failbit。
#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;
}
为什么std :: istream会认为出了什么问题?
答案 0 :(得分:2)
这样做的一个原因可能是lexical_cast
的实现可能会故意尝试导致某些流失败,以便检查是否已消耗所有输入文本。例如,一个天真的实现可能如下所示:
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;
}
这里的想法是最终检查试图打破流以查看是否遗留了某些内容。如果你启用了异常,这将把应该是failbit
检测到的普通流故障变成异常,这是代码没有预料到的。
但更一般地说,您不应该在提取例程中设置流设置。这取决于呼叫者。否则,无论您在调用提取例程之前尝试对流做什么,例程都将覆盖您的首选项。毕竟,如果我明确地禁用了异常然后发生异常,那就太糟糕了,因为你在operator >>
内重新启用了它们。
希望这有帮助!