1

我正在创建一个原始类型包装器,它可以使用 boost::lexical_cast 从字符串中设置其值。它工作正常,但由于某种原因 std::istream 提取运算符设置了故障位。以下程序打印:

123.45
例外:ios_base::failbit 设置

但是,如果您注释掉“inStream.exceptions(...”这一行,它会起作用并打印:

123.45
123.45

无论您是否使用 unicode 编译,或者如果您使用 int 或 float 作为 ValueType,都没有什么区别,在任何情况下都会设置故障位。

#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 会认为出了问题?

4

1 回答 1

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 >>

希望这可以帮助!

于 2011-09-07T22:14:37.780 回答