-3

If I use assignment operators or output functions inside the if condition, why is it taken as a "true" Boolean value?

For example, I do

if(cout << "a"){cout << "c";}

Or

if(int x=7){cout << "c";}

Or even

if(6){cout << "c";}

the outputs are indeed, "c" and "c" and "c" in each case. But we were told that, inside the if condition, we have to use an expression that finally evaluates to a Boolean value, like 1 or 0.

So what is the piece of information I am missing?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aditya Agarwal
  • 221
  • 2
  • 11
  • 4
    It doesn't have to be the bool value `true` or `false`. It just has to be [contextually convertible](https://en.cppreference.com/w/cpp/language/implicit_conversion#Contextual_conversions) to bool. See https://en.cppreference.com/w/cpp/language/if . – Justin Aug 14 '18 at 17:46
  • 4
    `int x=7` isn't assignment. it is initialization. – NathanOliver Aug 14 '18 at 17:47
  • @NathanOliver agreed (comment removed) but it compiles, live: https://godbolt.org/g/dSef3y Now trying to work out why. – Richard Critten Aug 14 '18 at 17:49
  • 1
    @RichardCritten Consider `if (auto opt = something_returning_optional()) { ... }`. That's valid and has been valid for a long time – Justin Aug 14 '18 at 17:50
  • @RichardCritten Yes, it will compile. The initialized variable is then converted to a bool and checked. – NathanOliver Aug 14 '18 at 17:50
  • 1
    @NathanOliver Thanks - still kind of strange `if(int x=7; int y=0){x=x;y=y}` is good – Richard Critten Aug 14 '18 at 17:52
  • @RichardCritten That is something C++17 introduced. Before you could only do `if(type name = initializer)` and `name` would be evaluated. Now, in C++17, you could do `if(type name = initializer; some_condition)` but since `some_condition` can be `type name = initializer` you can declare another variable and evaluate that variable. – NathanOliver Aug 14 '18 at 17:56
  • 2
    @RichardCritten Ah the magic of _init-statement_ in selection statements #C++17 – Lightness Races in Orbit Aug 14 '18 at 17:56

3 Answers3

3

In each case the expression is converted to a bool. The value of this bool is true in the three cases that you use (it may not always be true).

if(cout << "a"){cout << "c";}

In this case the expression:

   cout << "a"

If find the operator<<(std::ostream&, char const*) definition you will find that the return value is std::ostream&. So this will return a reference to the cout object (of type std::ostream). The stream object has a boolean conversion method explicit bool() which can be used to convert the object to bool. The result of this depends on the state of the object (if it is in a bad (failing) state it will return false).

So here you are checking that the last operation on the stream worked. If it does then print "c". This is commonly used on input streams to validate user intput.

int val;
if (std::cin >> val) {
    if (std::cout << "A value was correctly read\n") {
        // Add response worked.
    }
    else
    {
        // Something bad happened to std::cout
    }
}

In the other cases you use int variables. These can be implicitly converted to bool. If the value is non zero then it is true (otherwise false).

Martin York
  • 257,169
  • 86
  • 333
  • 562
1

Every value inside a condition (or with Boolean conversion) will give you true, unless it equal to 0.

(6)            returns => 6              != 0            => true
(x = 7)        returns => 7              != 0            => true
(cout << "aa") returns => ostream object.
                          bool context so calls `ostream::operator bool()`
                          If the stream is in good state => true
                          Otherwise                      => false

In C you can see it with NULL with this declaration:

#define NULL 0

which means that if an pointer equal to NULL it will return you a false in a Boolean conversion.

Examples in C++ for boolean expressions:

int a, b, *c;
char d;
bool e;

a = 0;
b = 2;
c = nullptr;

e = a; // false
e = b - 2; // false
e = c; // false

c = &a;
e = c; // true
e = b; // true
e = a + 1; // true
e = b ^ b; // false

d = 0;
e = d; // false
d = '0';
e = d; // true
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Coral Kashri
  • 3,436
  • 2
  • 10
  • 22
0

In all the cases you've shown, it's still true that you've provided an expression that eventually is convertible to bool. If you look at the << operator of std::cout and similar ostreams, you'll see they all return a reference to the same stream. This stream also defines a conversion to bool operator, which is implicitly called in a context where a bool is expected. This particular conversion returns true if the stream has no errors. Secondly, int x=7 is an initialization, and it returns the value that x was just initialized with; 7 in this case. int in C++ can be implicitly cast to bool to be true if it's not zero, which is why both 7 and 6 evaluate to true in the second and third examples.

alter_igel
  • 6,899
  • 3
  • 21
  • 40
  • Please note that the assignment operator is not called here. `if(int x=7){cout << "c";}` is syntatic sugar for `{ int x=7; if(x){cout << "c";}}` – NathanOliver Aug 14 '18 at 17:59
  • Can you explain a bit more in elementary terms please? I am new to Computer science, almost only a week. What are streams and all? – Aditya Agarwal Aug 14 '18 at 18:09
  • 1
    @AdityaAgarwal I would start at the beginning of a [recommended C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) and learn about basic language constructs and classes. As a beginner in school, the details of how `cout` probably won't matter, but as you get comfortable and if it interests you, read about implicit conversions and operator overloading. – alter_igel Aug 14 '18 at 18:14
  • In general, C++ has lots of hidden surprises that can haunt your code if you're not careful. Good practice and sticking to neat style and convention will keep things easy and predictable. – alter_igel Aug 14 '18 at 18:16