Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
288 views
in Technique[技术] by (71.8m points)

c++ - Evaluating stream operator >> as boolean

The following code compiles in Visual Studio 2008 but fails in Visual Studio 2013 and later.

std::string str("foo");
std::stringstream ss(str);
float f = 0;

if ((ss >> f) == false)
    std::cout << "Parse error
";

The error message is

error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::basic_istream>' (or there is no acceptable conversion)

and is successfully fixed by changing as follows:

if (!(ss >> f))
    std::cout << "Parse error
";

I'm not understanding this well. My question is, what operator or cast or maybe ios flags are involved that allow the stream read to be evaluated as a boolean in the first place, and then why does the lack of an operator== break it?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Two behaviors changed since C++11.

  1. The behavior of std::basic_ios::operator bool changed.

    operator void*() const;         (1) (until C++11)
    explicit operator bool() const; (2) (since C++11)
    

    Note since C++11 operator bool() is declared as explicit; but for if ((ss >> f) == false), ss (i.e. the return value of (ss >> f)) needs to be implicit converted to bool (to be compared with false), which is not allowed.

  2. The definition of the null pointer constant changed.

    Before C++11 operator void*() could be used and it's not explicit (before C++11 there's no such explicit user-defined conversion), and before C++11 the null pointer constant is defined as:

    an integral constant expression rvalue of integer type that evaluates to zero (until C++11)

    which means false could be used as a null pointer constant. So ss could be implicitly converted to void* and then compared with false (as the null pointer).

    From C++11, the null pointer constant is defined as:

    an integer literal with value zero, or a prvalue of type std::nullptr_t (since C++11)

    while false is not again; it's not an integer literal.

So, because of these two changes, if ((ss >> f) == false) won't work in C++11 and later.

On the other hand, if (!(ss >> f)) works fine because there's std::basic_ios::operator! (both before and after C++11) for it.

bool operator!() const;

Returns true if an error has occurred on the associated stream. Specifically, returns true if badbit or failbit is set in rdstate().

BTW: Since C++11, even without std::basic_ios::operator!, explicit operator bool() const could also make if (!(ss >> f)) works well, because in the context of contextual conversion, explicit user-defined conversion is considered; i.e. ss could be contextually converted to bool for operators !.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...