2011-09-07 45 views
1

我创建了一个原始类型包装,它可以使用boost :: lexical_cast从字符串中设置它的值。它工作正常,但由于某些原因,std :: istream提取操作符设置失败位。下面的程序打印:std :: istream提取设置无故障失败位

123.45
例外:的ios_base :: failbit设置

但如果你注释掉行 “inStream.exceptions(...” 它的工作原理和打印:

123.45
123.45

它不会有所作为,如果你使用Unicode编译或没有,或者如果你使用整数或浮点数为值类型,在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会认为出了问题?

回答

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 >>内部将它们拒之门外,这将是不好的。

希望这会有所帮助!

+0

对,这很有道理。所以基本上lexical_cast有责任去捕捉错误,所以我不应该强迫目标类去担心一些与它无关的故障点。由于lexical_cast不会抛出任何东西,所以一切都很好。我只需要删除“inStream.exceptions(...”行。 – zeroes00