Why is int x{ y = 5 } possible? - c++

int main() {
int y;
int x{ y = 5 };
//x is 5
}
How is this possible, since y = 5 is not a calculable expression?
Also, why doesn't the compiler or IDE complain about main() not returning an int?

How is this possible, since y = 5 is not a calculable expression?
It is an assignment, and assignments yield values, i.e. the "cv-unqualified type of the left operand", see [expr.ass/3]. Hence y = 5 results in y, which is 5, which is used to initialize x.
With respect to your second question, see cppreference on main (or [basic.start.main/5]):
The body of the main function does not need to contain the return statement: if control reaches the end of main without encountering a return statement, the effect is that of executing return 0;.
Hence, compiler or IDE warning you about a missing return statement at the end of main would be plain wrong. Admittedly, the fact that you should always return objects from non-void functions execpt main is kind of... well, for historical reason I guess.

I will start from your last question
Also, why doesn't the compiler or IDE complain about main() not
returning an int?
According to the C++ Standard (6.6.1 main function)
5 A return statement in main has the effect of leaving the main
function (destroying any objects with automatic storage duration) and
calling std::exit with the return value as the argument. If control
flows off the end of the compound-statement of main, the effect is
equivalent to a return with operand 0 (see also 18.3).
And relative to this question
How is this possible, since y = 5 is not a calculable expression?
From the C++ Standard (8.18 Assignment and compound assignment operators)
1 The assignment operator (=) and the compound assignment operators
all group right-to-left. All require a modifiable lvalue as their left
operand and return an lvalue referring to the left operand.
Sp this declaration
int x{ y = 5 };
can be equivalently split into two statements
y = 5;
int x{ y };
Moreover in C++ you can even to make a reference to the variable y the following way
int &x{ y = 5 };
Here is a demonstrative program
#include <iostream>
int main()
{
int y;
int &x{ y = 5 };
std::cout << "y = " << y << '\n';
x = 10;
std::cout << "y = " << y << '\n';
}
Its output is
y = 5
y = 10
You may this declaration
int x{ y = 5 };
rewrite also like
int x = { y = 5 };
However take into account that there is a difference between these (looking similarly as the above declarations) two declarations.
auto x{ y = 5 };
and
auto x = { y = 5 };
In the first declaration the variable x has the type int.
In the second declaration the variable x has the type std::initializer_list<int>.
To make the difference more visible see how the values of the objects are outputted.
#include <iostream>
int main()
{
int y;
auto x1 { y = 5 };
std::cout << "x1 = " << x1 << '\n';
auto x2 = { y = 10 };
std::cout << "*x2.begin()= " << *x2.begin() << '\n';
std::cout << "y = " << y << '\n';
return 0;
}
The program output is
x1 = 5
*x2.begin()= 10
y = 10

The operator=() results in a value, which is the value assigned to the variable. Because of this, it is possible to chain assignments like this:
int x, y, z;
x = y = z = 1;

If you take a look at the documentation on cppreference, you'll see that operator=() return a reference to the object that was assigned. Therefore, a assignment can be used as an expression that returns the object that was assigned.
Then, it's just a normal assignment with braces.

Related

Why is incrementing and assigning to a reference, not change the value?

I am not able to understand, why the output of the code is not what I was expecting.
#include <iostream>
using namespace std;
int main()
{
int m = 2, n = 6;
int &x = m;
int &y = n;
m = x++;
x = m++;
n = y++;
y = n++;
cout<< m << " " << n;
return 0;
}
I was expecting 4 8
This line:
m = x++;
is equivalent to:
x = x++;
since m is a reference to x.
From c++17, the right hand side is evaluated first, resulting in 2. Then x is incremented to 3. Then the assignment of the right hand side value to the left hand side is done. But this uses the old value of the right hand side, which is 2. So the above statement effectively does nothing.
Before c++17,
m = x++;
is undefined behavior.
Notice how the operators are post-increment and not pre-increment... You're basically doing nothing.
m = x++; means that increment x (i.e. m) but return the old value of x (i.e. m). Assignment takes place after the increment and return of old value and the old value is what ends up getting assigned. So, you end up essentially with a bunch of self-assignments.

Returning 0 after functions are called without "return(0);"

I'm having a small issue in trying to figure out why a zero is printed out at the end of my while loop.
#include <iostream>
using namespace std;
int x;
int CountDown(int x);
int CountUp(int x);
int main()
{
int toCountUp = CountUp(x);
cout << x << endl;
}
int CountUp(int x)
{
x = 0;
while(x <= 10)
{
cout << x << endl;
x++;
}
}
My best response would be that it is in the condition of the while loop. Or a return status from the function/main being fulfilled, but I don't have a return on there, and I know a function doesn't require a return statement but in this while loop I want there to be a integer returned, do I need to make the function void so there will be no return? But what about the parameter x that I need for the while loop?
code output:
0
1
2
3
4
5
6
7
8
9
10
0 < ---- this is the number I do not want.
Thinking about it, it has to be a value returned at the end of the function, any ideas?
This outputs the values 0 through 10:
int toCountUp = CountUp(x);
Then, this outputs 0:
cout << x << endl;
The method does not change the value that is passed to it, it uses its own local copy of that variable.
—It's mainly because you are printing cout << x << endl; twice. Once in the int CountUp(int x) function itself, but again in the main function.
—It could've printed any given value of x at this point, but since you're setting x=0 outside of the While{} loop in the int CountUp(int x) function, it's printing 0 at the end after the function call is executed.
*int CountUp(int x)
{
x = 0;
while(x <= 10)
{
cout << x << endl;
x++;
}
}*
—Is there a reason why you are setting x=0 within the function? since you're passing x as a parameter in the function call, and adding 1 to it in the While{} loop until it's x<= 10? Asking because you're not returning x back to the main() function.
—In case you wanted to use the end value of x to countdown using CountDown(x), you may like to reset x=0 in the main() function after calling the block—
*int CountUp(int x)
{
x = 0;
while(x <= 10)
{
cout << x << endl;
x++;
}
}*
At last 0 is printed in main() function because x is declared global.
If you want latest x after loop got over to be printed in main() then you should reference variable and don't declare it globally.
int CountUp(int &); /* function prototype*/
Since passed variable(actual argument) and reference variable having the same memory So modification will affects in calling function.
int CountUp(int &x) { /* catch with reference variable so that modification affects in calling function also */
x = 0;
while(x <= 10)
{
cout << x << endl;
x++;
}
}
First read Shadowing variables and What's the difference between passing by reference vs. passing by value?
The int x parameter of CountUp shadows the global variable int x so inside CountUp, the only x is the parameter.
int CountUp(int x)
int x defines x as passed by value, so it is a copy of the x used to call CountUp in main. This different x is counted up to 10 and then discarded.
the global int x has static storage duration and is default initialized to zero for you. Do not try this trick with a variable with Automatic duration because unless it has a constructor that does something useful, the contents are uninitialized and their value is undefined.
Sideshow issue:
A function that has a non-void return type MUST return a value on ALL paths. If it does not, you have Undefined Behaviour and the compiler can generate hopelessly invalid code that can get you even if the bad path is not taken. Don't smurf with Undefined Behaviour, as it might crash the program or do something hilariously wrong, but it might also look like it works until it suddenly doesn't at a really bad time.
Solutions:
void CountUp(int & x)
{
x = 0;
while(x <= 10)
{
cout << x << endl;
x++;
}
}
Passes x by reference allowing global x and the local x to be one and the same and returns nothing.
Usage would be
CountUp(x);
Not so useful in the asker's case because it doesn't leave a toCountUp.
int CountUp(int x)
{
x = 0;
while(x <= 10)
{
cout << x << endl;
x++;
}
return x;
}
Makes a copy if the provided x, operates on the copy, and then returns x. Usage would be
int toCountUp = CountUp(x);
And will set toCountUp to 10 higher than the global x.

Compound operation evaluation in C++

When I execute the following code
#include <iostream>
int & f(int &i)
{
puts("this is f");
return ++i;
}
int main()
{
int x = 5;
printf("%d", f(x) = f(x) + 1);
return 0;
}
I get output as 8. I am unable to understand how that's happening. Can anyone give me a reason for that?
It's unspecified which of the two calls to f(x) occurs first; and if the right-hand-side one was called first, it's unspecified whether the prvalue conversion of that occurs before or after the call to the left-hand-side's f(x). But all of those happen before the assignment.
One valid order is:
lhs f(x)
rhs f(x)
rvalue conversion
which results in i = 7 + 1;.
Alternatively it could be:
rhs f(x)
rvalue conversion
lhs f(x)
which results in i = 6 + 1;
There is no undefined behaviour relating to the ++ operator, because there is a sequence-point before and after each function call.
Refs:
[intro.execution]#15
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced
[expr.ass]#1
In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.
In this quote, "the value computation of the assignment expression" means the value that this expression takes if it's a sub-expression of a larger expression, e.g. bar = ( foo(x) = foo(x) + 1 );
This code will let you inspect which order your compiler is using. I have inserted bar which passes its value through unmodified.
#include <cstdio>
using namespace std;
int & f(int idx, int &i)
{
printf("this is f %s\n", idx ? "right" : "left");
return ++i;
}
int bar(int idx, int z)
{
printf("bar%d = %d\n", idx, z);
return z;
}
int main()
{
int x=5;
f(0,x)= bar(0, bar(1, f(1,x)) + 1 );
printf("final = %d\n",x);
return 0;
}
Output for my system:
this is f left
this is f right
bar1 = 7
bar0 = 8
final = 8
Output for Coliru:
this is f right
bar1 = 6
bar0 = 7
this is f left
final = 7
Look how this line of code is evaluated:
printf("%d",f(x)=f(x)+1);
Step 1:
Initialization of x
--> x == 5
Step 2:
First call of f (right side of equals sign)
--> x == 6
Step 3:
Adding 1
--> x == 7
Step 4:
Second call of f (left side of equals sign)
--> x == 8
EDIT(see comment for deeper insight & thx to Matt):
You use reference parameter. When you modify the variable x in the f function, you modify too in main function.
First x = 5
When you call f first time, x = 6
When you call f second time, x = 7
Finally, 7 + 1 = 8
Function parameter i is a reference to int x.
So, ++i is actually incrementing x.
f(x) is called twice with initial x=5 which will make x equal to 7.
But 1 is added at printf, making final value printed 8.
#include <iostream>
int & f(int &i)
{
puts("this is f");
return ++i;
}
int main()
{
int x=5;
//f(x)=f(x)+1 equals to following
int& tmp_x = f(x); //x=6
int tmp = f(x)+1; //x = 7, tmp = 8
tmp_x = tmp; //x=8
printf("%d",tmp_x);
return 0;
}

Box2D vector () operator

I was reading the Box2D source code. In b2Vec2 there is the () operator being overloaded, but I did not understand what it is supposed to do. I read the manual and the reference of this method but still did not get what it means to Read from an indexed element and write to an indexed element, and both methods have the same body return (&x)[i]. What does this mean and do?
Thanks to a previous comment (but it was removed for some reason), I got an idea and tested it out, and it turns out this will allow me to access and write to x and y using indices 0 and 1 respectively.
For example:
#include <iostream>
using namespace std;
class clazz {
public:
float x, y;
clazz(float x_, float y_) : x(x_), y(y_) {}
float operator () (int i) const {
return (&x)[i];
}
float& operator () (int i) {
return (&x)[i];
}
};
int main() {
clazz f (3, 4);
cout << "f: x = " << f(0) << " y = " << f(1) << endl; // printed => f: x = 3 y = 4
f(0) = 6;
f(1) = 6;
cout << "f: x = " << f(0) << " y = " << f(1) << endl; // printed => f: x = 6 y = 6
return 0;
}
As you found out it's an accessor function to the individual elements in the vector class. The reason there are two functions is due to const functions need access to the value of the element without needing to modify it. Note that you could return a const reference here as well but this is not necessary in your case since it is operating on a float.
Hopefully there are asserts in place for making sure that code isn't indexing out of the range since that is quite easy to do, especially when you have are using a signed variable like in your example.

How do I emulate C++ postfix in bison?

I am trying to implement a simple compiler using flex & bison, and got stuck in the postfix notation.
(The compiler should behave like the C++ compiler)
Here is the problem:
Given the following code:
int x = 0;
int y = x++ || x++ ; //y=1 , x = 2 this is understandable
int z = x++ + x++ ; // z = 0 , x=2
the first line is fine because of the following grammar:
expression = expression || expression; // x=0
expression = 0 || expression // x= 1
expression = 0 || 1 //x=2
expression = 1 // x=2
y = 1
However, I don't understand why z=0.
When my bison grammar sees 'variable' ++ it first returns the variables value, and only then increments it by 1. I used to think thats how C++ works, but it won't work for the 'z' variable.
Any advice on how to solve this case?
int z = x++ + x++;
Although z may appear to be 0, it is not, it could in fact be any value and will depend entirely upon the compiler you are using. This is because the assignment of z has undefined behaviour.
The undefined behaviour comes from the value of x being changed more than once between sequence points. In C++, the || operator is a sequence point which is why the assignment of y is working as expected, however the + operator is not a sequence point.
There are of course various other sequence points in C++, the ; being a more prominent example.
I should also point out that the ++ operator returns the previous value of the variable, that is in this example
#include <iostream>
using namespace std;
int main() {
int x = 0;
int y = x++;
cout << y << endl;
return 0;
}
The value printed out for y is 0.
Saying the same thing another way. A C compiler is free to implement
int z = x++ + x++;
as either
z = x + x
incr x
incr x
or as
int r1 = x;
incr x
z = r1 + x
incr x
Your compiler appears to be using the first plan.