Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

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

1 Answer

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...