62

I have been using "Accelerated C++" to learn C++ over the summer, and there's a concept which I don't seem to understand properly.

Why is

int x;
if (cin >> x){}

equivalent to

cin >> x;
if (cin){}

By looking at the code, it seems to me that we're using cin as a variable. But, I thought it was a function. Why can we use cin in this way when it is x that has whatever value we input into our keyboard?

Trojan
  • 2,256
  • 28
  • 40
Muhsin Ali
  • 621
  • 1
  • 6
  • 3

9 Answers9

78

cin is an object of class istream that represents the standard input stream. It corresponds to the cstdio stream stdin. The operator >>overload for streams return a reference to the same stream. The stream itself can be evaluated in a boolean condition to true or false through a conversion operator.

cin provides formatted stream extraction. The operation cin >> x;

where "x" is an int will fail if a non-numeric value is entered. So:

if(cin>>x)

will return false if you enter a letter rather than a digit.

This website on tips and tricks using C++ I/O will help you too.

  • Sorry, that's too technical for me. I haven't gotten onto classes or anything like that. Why do we use boolean? – Muhsin Ali Jul 22 '11 at 14:53
  • 1
    @Muhsin Ali: Trying to understand different things one stumbles across is generally good when learning something new. However in this case, I would recommend you to just regard `cin` and `cout` as "magic" for now. Of course they are not magic, but they are built using a number of quite advanced techniques. It is probably better to go on for now and then get back once you've mastered classes, inheritance and operator overloading. – Anders Abel Jul 22 '11 at 14:59
  • 4
    @Muhsin: Because all that `if` accepts as the if expression is a boolean, an integer, or a pointer. The class `std::istream` provides the ability to convert an input stream to a boolean, and it is this conversion operator that is used in evaluating whether to perform the `if` branch or the `else` branch. – David Hammen Jul 22 '11 at 15:02
  • 1
    @Muhsin: If cin is presented with data it cannot process, it goes into a "fail state" so you have check it with an if statement. Go to the link I provided my last sentence. There is a code sample there. –  Jul 22 '11 at 15:03
  • @Muhsin : `cin` is object of `istream` , which has overloaded operator >> for all built in types. see this like : `cin.operator>>(x);` , that is operator `>>` is nothing but member function of `cin`. For more clarification read answer of David [link](http://stackoverflow.com/questions/6791520/if-cin-x-as-a-condition/6791854#6791854) –  Jul 22 '11 at 15:04
  • @David Hammen: Feeling in a very pedantic mood (its one of those mornings). It provides the ability to convert the stream into a type(unspecified) that can be used in a boolean context (boolExpr (ie anything that autoconverts to bool)). (Note: This has been changed to bool in the latest unreleased version C++0x (but is still not supported by most compilers)). – Martin York Jul 22 '11 at 15:52
  • 1
    @DavidHammen *std::istream provides the ability to convert an input stream to a boolean, and it is this conversion operator that is used...* Could you please tell me about the conversion operator isteam provides? – Quazi Irfan Oct 14 '13 at 22:39
  • @iamcreasy - I answered your question 2 years ago! See my answer below. Also note that my answer is for C++03. Things work a bit differently in C++11, but with the same end result of performing the then clause of the `if` statement if the stream extraction succeeds. – David Hammen Oct 15 '13 at 06:39
  • @DavidHammen Thanks. My bad, I missed it. Now it feels like a chain. One more question, what the difference between C++03 and C++11 in this context? – Quazi Irfan Oct 16 '13 at 11:01
  • so `cin` returns value of `cin.good()`? What about something like `cin >> a >> b`? Is the value returned corresponds to the last input? – Sourabh Oct 28 '14 at 17:01
39

Note: Answer updated four years after the fact to address both C++98/03 and C++11 (and beyond).


std::cin is an instance of a std::istream. That class provides two overloads that pertain to this question.

  • operator >> reads data from the stream into the target variable if that is possible. If the immediate contents of the stream cannot be translated into the type of the target variable, the stream is instead marked as invalid and the target variable is left untouched. Regardless of the success/failure of the operation, the return value is a reference to the stream.
  • Either operator void*() (pre-C++11), which converts the stream reference to a void* pointer, or explicit operator bool() (C++11), which converts the stream reference to a boolean. The result of this conversion is a non-null pointer (pre-C++11) or true (C++11) if the stream is valid, but the null pointer (pre-C++11) or false (C++11) if the stream isn't valid.

An if statement needs either a boolean, an integer, or a pointer as the quantity to be tested. The result of std::cin >> x is a reference to an istream, which is none of the above. However, the class istream does have those conversion operators which can be used to transform the istream reference to something usable in an if statement. It is the version-specific conversion operator that the language uses for the if test. Since failure to read marks the stream as invalid, the if test will fail if the read didn't work.

The reason for the more convoluted operator void* conversion member prior to C++11 is that it wasn't until C++11 that the already existing explicit keyword was extended to apply to conversion operators as well as constructors. A non-explicit operator bool() would have presented far too many opportunities for programmers to shoot themselves in the foot. There are problems with operator void*() as well. The "safe bool idiom" would have been a fix, but simply extending explicit accomplished exactly what the safe bool idiom accomplishes, and without having to use a lot of SFINAE magic.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • 6
    It doesn't use `operator bool` but rather `operator void*`, operator bool would allow it to be used in arithmetical contexts whereas operator void* prevents this since void is an imcomplete type. In the implementation of the MSVC compiler operator void* returns the address of the object if no fail flag is set (which can't be 0 and therefore it's evaluated as `true` in a boolean context) or 0 if any flag is set (evaluating to boolean false). – lccarrasco Jul 22 '11 at 15:35
  • 2
    According to http://www.cplusplus.com/reference/ios/ios/operator_bool/ it is `operator void*()` for C++98 and `operator bool()` for C++11. – Evgeni Sergeev Aug 13 '15 at 04:23
  • @DavidHammen `std::cout<<(std::cin>>x);` if this fails gives output `0` and if succeed gives output `0x486650` why then it not give `1`. Also I didn't get exactly what are you saying `It is the version-specific conversion operator that the language uses for the if test.` – Abhishek Mane Aug 19 '21 at 13:41
  • 1
    @AbhishekMane `std::cout<<(std::cin>>x);` fails to compile with a modern compliant compiler unless you tell it to compile against the C++98 standard (e.g., `--std=c++98`). In all versions of the standard, the return value from `std::cin>>x` is a reference to the `std::cin` object, and there is no overload `std::basic_ostream operator>> (const std::basic_istream&)`. Pre-C++11, the compiler would use `std::basic_istream::operator void*()`. This returns the null pointer if the input failed, a non-null pointer if the input succeeded. That's why you're seeing `0` or `0x48650`. (continued) – David Hammen Aug 19 '21 at 14:41
  • 1
    The `void*` conversion operator was deleted in C++11, replaced with `explicit operator bool()`. The `explicit` tag (new in C++11) explicitly tells the compiler not to use that conversion in `std::cout<<(std::cin>>x)`. That expression should result in a compilation error in a compliant compiler that is compiling against the C++11, C++14, C++17, or C++20 versions of the standard. – David Hammen Aug 19 '21 at 14:44
  • 1
    @AbhishekMane In the case of `if (std::cin>>x)` one is implicitly asking for a conversion to a `bool`. This worked in a pre-C++11 environment because even though `std::istream` didn't have an `operator bool`, it did have `operator void*`, and a `void*` can easily be converted to a `bool`. This works in a C++11 and beyond environment without having to write `if (bool(std::cin>>x))` because this is one of the few places in C++11 and beyond where an expression that can be "contextually converted to bool" is allowed, even in the case of `explicit operator bool()`. – David Hammen Aug 19 '21 at 15:02
  • @DavidHammen first of all thanks. Now I understand. you said `void*` can easily be converted to a `bool` but How ? and 2nd one is *`'There are few places in C++11 and beyond where an expression that can be "contextually converted to bool" is allowed, even in the case of explicit operator bool()*'' can you mention some of these few places apart from loops. – Abhishek Mane Aug 21 '21 at 14:21
  • I get answer for my 2nd Question https://stackoverflow.com/q/39995573/11862989 user made question-answer type. Now just answer 1st one please. – Abhishek Mane Aug 21 '21 at 14:40
  • 1
    @AbhishekMane The implicit conversion of numbers and pointers to a `bool` in the context of `if (foo)` has been a part of C++ since day 1. If `foo` is a numeric type, `if (foo)` is equivalent to `if (foo != 0)`. If `foo` is a pointer type, `if (foo)` is equivalent to `if (foo != NULL)` (or better, if one is using C++11 or beyond, `if (foo != nullptr)`). A pointer-type converts to `false` if the pointer is null, `true` otherwise. Personally, I would rather see an explicit comparison to the null pointer in code I write or review, but at the same time I do realize that `if (foo)` is valid. – David Hammen Aug 21 '21 at 15:01
  • @DavidHammen Got it. Just Clear explanation. Thanks Man. – Abhishek Mane Aug 21 '21 at 15:09
  • @DavidHammen *"Personally, I would rather see an explicit comparison to the null pointer in code I write or review, but at the same time I do realize that if (foo) is valid."* I didn't get this. Can you elaborate please. – Abhishek Mane Aug 21 '21 at 15:34
  • 1
    @AbhishekMane I'm not a fan of the implicit conversion to`bool`. For example, assuming `foo` is a pointer type, I far prefer to see `if ((foo != nullptr) && foo->is_valid())` over `if (foo && foo->is_valid())`. But that's personal preference. Given a halfway decent compiler, the two statements are identical in terms of generated assembly code. – David Hammen Aug 21 '21 at 16:28
7

cin is a (global) variable of type istream, not a function.

The istream class overrides the >> operator to perform input and return a reference to the object you called it on (cin).

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
7

cin is variable in std namespace.

operator>> return reference to cin, because of it you can write: cin >> a >> b, instead of cin >> a; cin >> b;

Olympian
  • 758
  • 1
  • 6
  • 13
6

The answers above are informative. Here I just give an extra comment.

std::cin is an object of class istream and represents the standard input stream (i.e. the keyboard) which corresponds to stdin in C stream.

cin >> x would firstly read an int from the standard input stream and assignment it to x. After that return a self reference to cin. So the return value of function call cin >> x is still cin.

So from the point of if condition, if(cin) and if(cin >> x) resemble each other. The standard IO Library defines a function for the stream like this (depends on implementation):

explicit operator bool() const; // C++11

or

operator void*() const; //C++98, C++2003

From this two declarations, we know they cast the stream type directly or indirectly(through void* pinter to bool which is obvious) to bool type.

Within this two functions, they depends on some basic IO steam statuses(class fields) to determine whether return false or true (for void* case, it is nullptr or not).

cin is an instance of class istream which inherits the casting-to-bool function. So it works!

Zachary
  • 1,633
  • 2
  • 22
  • 34
5

because the result of the expression

cin >> x

evaluates to

cin

after the stream is read.

Erix
  • 7,059
  • 2
  • 35
  • 61
  • So that means I can call on cin and it will still have that value of x, until I overwrite it? – Muhsin Ali Jul 22 '11 at 14:52
  • Nope, cin will always be an instance of istream. But the variable x will continue to hold its value so there would be no need to get it from the stream again anyway. – Erix Jul 22 '11 at 15:19
2

std::cin is an instance of the std::istream class.

cin >> x is just calling a function on the cin object. You can call the function directly:

cin.operator >>(x);

To allow you to read multiple variables at once the operator >> function returns a reference to the stream it was called on. You can call:

cin >> x >> y;

or equivalently:

cin.operator >>(x).operator >>(y);

or:

std::istream& stream = cin.operator >>(x);
stream.operator >>(y);

The final part of the puzzle is that std::istream is convertible to bool. The bool is equivalent to calling !fail().

So in the following code:

int x;
std::istream& stream = std::cin.operator >>(x);
bool readOK = !stream.fail();
if (readOK)
{
  std::cout << x << "\n";
}

bool readOK = !stream.fail(); can be reduced to just bool readOK = stream;.

You don't need a separate bool to store the stream state so can just do if (stream).

Removing the temporary stream variable gives if (std::cin.operator >>(x)).

Using the operator directly gets us back to the original code:

int x;
if (std::cin >> x)
{
  std::cout << x << "\n";
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • `std::cout<<(std::cin>>x);` if this fails gives output `0` and if succeed gives output `0x486650` why then it not give `1` . – Abhishek Mane Aug 19 '21 at 10:41
  • 1
    @AbhishekMane I'm not sure what you mean but you could always open a new question with more details. `std::cout<<(std::cin>>x);` doesn't compile for me – Alan Birtles Aug 19 '21 at 11:24
  • https://stackoverflow.com/q/68849622/11862989 I asked question. please answer. Also https://stackoverflow.com/a/6791854/11862989 in this answer he mentioned `It is the version-specific conversion operator that the language uses for the if test.` which I think related to my Question but I am not getting it. – Abhishek Mane Aug 19 '21 at 14:22
1

1) cin is an instance of istream, see http://www.cplusplus.com/reference/iostream/cin/.

2) the >> operator of istream will return its left operand, in this case it is cin, see http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/. This operator will set failbit on if no characters were extracted from the cin, in case the reader has finished EOF so there will be no more character to read.

3) As of the 2) above, when the condition is evaluated after the reading operation, if (cin >> x) should be like if (cin), refer to this link http://www.cplusplus.com/reference/ios/ios/operator_bool/ you will see that, this if block will return:

  • A null pointer if at least one of failbit or badbit is set. Some other value otherwise (for C++98 standard).

  • The function returns false if at least one of these error flags is set, and true otherwise. (for C++11 standard)

Ryan Le
  • 1,357
  • 12
  • 7
0

because cin is an object of class, read more on http://www.cplusplus.com/reference/iostream/cin/ .

Emil Condrea
  • 9,705
  • 7
  • 33
  • 52