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

この理由の1つは、の実装が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 に答える