Using ++ as a prefix to a statement of access through class member not causing an error - c++

I am kind of confused right now, I was running the following code:
std::vector<int> test{1, 5, 10};
++test.at(1); // I'm trying to increment that number 5 to six, which works
std::cout << test.at(1) << std::endl; // Prints out 6 to the console
I was expecting it to give me a compiler error because as I had read from about the operator precedence that the . (for member access) and the increment operator (++) have the same precedence, but they read left to right on a statement, from what I understood anyways. So in the code shown above I thought it would have been equal to saying (++test).at(1), which obviously causes a compiler error. Why isn't that the case even though the associativity is left to right, why is it reading it (from what I think) like this... ++(test.at(1))? If they have the same precedence wouldn't it, just like in maths, for example, use the ++ first and then the .?

True, postfix increment (a++) and member access (.) have the same precedence.
But you're using prefix increment (++a).
Consult cppreference's precedence chart.
Indeed, test++.at(i) would error for the reasons you give, though as readers of the code we would not be in any way surprised in that case.

Function calls have a higher operator precedence than unary operators like "++". The function call at() gets resolved first, and so the increment operator takes place on what it returns instead of the container.
https://en.cppreference.com/w/cpp/language/operator_precedence
EDIT: As Asteroids With Wings pointed out in their answer, only the prefix version of "++" has lower precedence than the function call. The postfix "++" is at the same level of precedence.

Related

Operator precedence - increment versus member access

Consider this:
++iterator->some_value
Will the iterator be forwarded before some_value is accessed?
According to cppreference increment and member access both have the same precedence of 2. Does the order in which they are listed matter? Or is this undefined - compiler specific?
Note that preincrement and postincrement have different precedences, so the code snippet you've posted doesn't quite match the explanatory text you've linked.
The preincrement operator has a lower precedence than the member access operator, so ++iterator->some_value is the equivalent of ++(iterator->some_value).
If instead you had iterator->some_value++ where they both had the same precedence, then the left-to-right associativity comes into effect, and it would be processed as (iterator->some_value)++.
The member access operator -> has higher precedence over the prefix increment operator. Thus the expression ++iterator->some_value is grouped as if you had written
++(iterator->some_value)
On the other hand, if your were to write the expression iterator->some_value++ then since both the member access operator -> and the postfix increment operator have the same precedence, so left-to-right associativity will be used, which will make this expression equivalent to writing :
(iterator->some_value)++

C++: why is iter++->empty() legal?

Exercise 4.20 of C++ Primer, 5e asks whether the expression iter++->empty(); is legal. Assume that iter is a vector<string>::iterator.
This expression is legal. I compiled it with gcc, and the answers to another question on Stack Overflow have addressed this much. However, I'm confused as to why it is legal.
This answer to a similar question gives the following as an equivalent pair of expressions:
iter->empty();
iter++;
The operator precedence table in my book lists -> as having higher precedence than the postfix ++ operator. This matches the explicit order of operations in the equivalent code above. However, I am used to seeing operators apply to whatever is right next to them. In the case of ->, I expected the compiler would to apply it to ++ (by itself, without iter) and throw an error. In other words, I tried to parenthesize the original expression as iter(++->empty());, which is obviously illegal.
So, it seems like c++ requires compilers to parse expressions in a more complex way than just parenthesizing based on precedence and associativity. Is that right? If there is an easy way to explain how this actually happens, I would like to know about it.
Per cppreference, ++ and -> have the same precedence and have left to aright associativity. That means that iter++ is executed first, and then ->empty() is applied to the result of iter++, which is just iter (from before the increment) since it is postfix increment.

dot operator order of evaluation in c++

I am reading "C++ Primer (5th Edition)" and I've run in something I'm not sure I understand correctly.
The example is pretty much similar to one they gave in the book. Imagine we have some function that returns string (or any class that has non-static members):
string some_function(par1, par2) {
string str;
// some code
return str;
}
I know that you can use the return value of any function to access its members, i.e. something like this is valid:
auto size = some_function(arg1, arg2).size(); // or whatever member of class
However, since the dot operator . and function call operator () have left to right grouping and same precedence, the above expression should be something like this:
(some_function(arg1, arg2)).size()
I suppose I am right so far? The thing I don't understand here is order of evaluation. Since order of evaluation is not specified for . operator, it means that either some_function(arg1, arg2) or size() will be evaluated first. But how can it evaluate size() first if it doesn't know on which object is it working on? This implies that order of evaluation should be fixed from left to right, but it is not. How is this possible?
Another example is something like this:
cin.get().get();
Again, it seems like first cin.get() should be evaluated before second get() since it won't know on which object is it working, but this doesn't seem to be necessarily the case.
Operators of the same precedence are evaluated according to their associativity, which you correctly observe is left-to-right for the operator group containing the function call and element selection operators. Therefore, yes, given the expression
x = foo().bar();
The order of operations is
x = (((foo()).bar)());
accounting for relative precedence and associativity of all operators involved. No one writes code in that manner, though.
Likewise, given
cin.get().get()
the order of operations is
(((cin.get)()).get)()
, so yes, the precedence rules result in the cin.get() sub-expression being evaluated first, yielding the object to which the second . (and thence the rest of the expression) is applied.

How do I set a precedence value to operators such as '*', '/', '+', and '-.

I either want to set them to bool values or simply integer values so that I can tell my function to multiply/divide these two integers before I add/subtract them to another operand.
Here is my code:
while (!S.empty() && **PRECEDENCE**next <= **PRECEDENCE**S.top())
{
temp = S.top();
S.pop();
postfix.append(temp);
}
Where S is for the stack. So let's say next is the * token and S.top() is '+', so * takes priority over +, so I need to assign a value to * and + so that when they are compared to one another, their values are compared. So the value of * is 1 whereas the value of + is 0.
OMG, there are many methods to do this.
Look up table
You could create a table of records and search the table for the operator, then retrieve the precedence value.
Use switch statement
I don't advise, but it is similar functionality of mapping a precedence to an operator.
Use std::map
Same concept as the other two, except using std::map<char, int> for operator character and precedence.
Hard code the precedence
The operators you compare for first will have the highest precedence. The next operators checked will have lower precedence.
Search the Web and StackOverflow
Hint: Other people have done this assignment. Search StackOverflow or the web for:
"c++ postfix operator precedence"
"c++ calculator operator precedence"
"c++ calculator operator evaluation"
"c++ postfix operator evaluation"
Or use other synonyms that I haven't listed.
Research before posting
Be as smart person and cheat by researching and seeing what other people have done. Before posting questions here.
Use a debugger
Use a debugger or print statements to see where your issues lie.
If you are still stumped, post the issue, your minimal code and the expected behavior.

Explain the difference:

int i=1,2,3,4; // Compile error
// The value of i is 1
int i = (1,2,3,4,5);
// The value of i is 5
What is the difference between these definitions of i in C and how do they work?
Edit: The first one is a compiler error. How does the second work?
= takes precedence over ,1. So the first statement is a declaration and initialisation of i:
int i = 1;
… followed by lots of comma-separated expressions that do nothing.
The second code, on the other hand, consists of one declaration followed by one initialisation expression (the parentheses take precedence so the respective precedence of , and = are no longer relevant).
Then again, that’s purely academic since the first code isn’t valid, neither in C nor in C++. I don’t know which compiler you’re using that it accepts this code. Mine (rightly) complains
error: expected unqualified-id before numeric constant
1 Precedence rules in C++ apply regardless of how an operator is used. = and , in the code of OP do not refer to operator= or operator,. Nevertheless, they are operators as far as C++ is concerned (§2.13 of the standard), and the precedence of the tokens = and , does not depend on their usage – it so happens that , always has a lower precedence than =, regardless of semantics.
You have run into an interesting edge case of the comma operator (,).
Basically, it takes the result of the previous statement and discards it, replacing it with the next statement.
The problem with the first line of code is operator precedence. Because the = operator has greater precedence than the , operator, you get the result of the first statement in the comma chain (1).
Correction (thanks #jrok!) - the first line of code neither compiles, nor is it using the comma as an operator, but instead as an expression separator, which allows you to define multiple variable names of the same type at a time.
In the second one, all of the first values are discarded and you are given the final result in the chain of items (5).
Not sure about C++, but at least for C the first one is invalid syntax so you can't really talk about a declaration since it doesn't compile. The second one is just the comma operator misused, with the result 5.
So, bluntly, the difference is that the first isn't C while the second is.