9
#include <stdio.h>

int main()
{
   int i = 10;
   printf("%d\n", ++(-i)); // <-- Error Here
}

What is wrong with ++(-i)? Please clarify.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Wei
  • 93
  • 1
  • 3
  • 2
    Even if it *would* do something reasonable I would still beg you to rewrite it in a way that makes sense to people who will read your code later – Dyppl Jun 03 '11 at 17:13

4 Answers4

10

-i generates a temporary and you can't apply ++ on a temporary(generated as a result of an rvalue expression). Pre increment ++ requires its operand to be an lvalue, -i isn't an lvalue so you get the error.

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • I don't think its a correct answer. You can apply `++` on a temporary : http://www.ideone.com/cv9oI – Nawaz Jun 03 '11 at 17:10
  • @Nawaz : Not on temporaries generated by rvalue expressions. Edited my post. – Prasoon Saurav Jun 03 '11 at 17:13
  • @Nawaz : You are allowed to invoke member functions on temporaries. – Prasoon Saurav Jun 03 '11 at 17:21
  • @Prasoon: But you said I cannot apply `++` on temporaries generated by rvalue expressions, which is misleading, because I can. – Nawaz Jun 03 '11 at 17:23
  • 1
    I think SLaks has the correct term for this. It's not temporaries but r/lvalues. – Captain Giraffe Jun 03 '11 at 17:23
  • ++(a()) isn't a prvalue. (-i) is. (-i) doesn't return a reference. You can't do ++(-a()) either. – Lee Louviere Jun 03 '11 at 17:23
  • @Xaade: `prvalue` is a C++0x concept, while we're discussing C++03. And I can do even `++(-a())` also: http://www.ideone.com/361fL – Nawaz Jun 03 '11 at 17:24
  • @Nawaz So it is, however it was formulated to define categories of expressions. The same rules apply to whether the expression has an identity or not. The only difference is a question of whether expressions can be moved. – Lee Louviere Jun 03 '11 at 17:26
  • 1
    @Nawaz: §5.3.2 *The operand of prefix ++ is modified by adding 1, or set to true if it is bool (this use is deprecated). The operand shall be a modifiable lvalue. The type of the operand shall be an arithmetic type or a pointer to a completely-defined object type. The value is the new value of the operand; it is an lvalue.* The example you provide is different in that it is a member function operator, and as such it behaves as any other member function, and those don't need to be applied to an lvalue. – David Rodríguez - dribeas Jun 03 '11 at 17:26
  • I'd just change the wording to "you can't apply built-in `++` to a rvalue" - since you're allowed to call member functions on rvalues of class type (i.e. temporaries). – Vitus Jun 03 '11 at 17:27
  • @David: I was discussing the terminology @Prasoon has used in his answer: `temporary` vs. `lvalue` vs `rvalue`. Usage of the term *temporary* here is a bit misleading. – Nawaz Jun 03 '11 at 17:29
  • http://www.ideone.com/2k3Fw. It's an lvalue now. Therefore has an identity, therefore can be used to increment. Just because it doesn't have a variable as a reference, doesn't mean it's not an lvalue. Move is a C++0x concept, but the rules of l/rvalue and which has identities are the same. – Lee Louviere Jun 03 '11 at 17:35
  • 2
    @Nawaz: I don't think so. You stated that the answer was unconvincing since you could do something similar with a **member** `operator++`, which is a completely unrelated problem. Consider `struct A {}; A operator++( A & ); ++A();` Ooops... you cannot call `operator++` there. You *changed* the problem (from a built in preincrement to a member preincrement) and then stated that this answer does not solved your *modified* problem. And after it has been explained to you what the difference is, you are not able to accept that you made a mistake. All of us make mistakes, that is how we learn. – David Rodríguez - dribeas Jun 03 '11 at 17:41
  • @Nawaz @David @Prasoon The point of this discussion, is that a temporary can be incremented. Didn't I just demonstrate that. – Lee Louviere Jun 03 '11 at 17:41
  • @David: I said the usage of the term *temporary* is a bit misleading. How can you say its not misleading? Also, the original answer was more misleading than the edited one. – Nawaz Jun 03 '11 at 17:48
  • @Nawaz : It was not misleading. Check out the question again. Does it say anything (at all) about user defined types? Yes? – Prasoon Saurav Jun 03 '11 at 17:50
  • 3
    @Xaade: You should replace the `main` with `++(-A())`, currently there are no temporaries in the program. And I never claimed that you cannot have an lvalue expression referring to a temporary (there are many ways of doing it), but I still find it amusing that the same people over and over, and without really understanding the issue nitpick on others just because they can write some similar (not equivalent) code that seems to work. I would have taken it much better if there was some constructive criticism on the terminology (I just did it in Slaks answer about 10min ago) – David Rodríguez - dribeas Jun 03 '11 at 17:51
  • @Prasoon: If it was not misleading, then ask yourself : why did you edit the answer and added this `(generated as a result of an rvalue expression)`? :P. The edit shows that for a moment even you did think that it was misleading, and so you added this to make your answer more accurate, and less misleading. – Nawaz Jun 03 '11 at 17:52
  • @Xaade: and there is a lot to nitpick in that comment... *variable* is still misleading, as there are --and you have just proven it-- expressions that yield lvalues that are not *variables*. But that is a complete different discussion. – David Rodríguez - dribeas Jun 03 '11 at 17:53
  • 2
    @Nawaz: Your exact comment was: *I don't think its a correct answer. You can apply ++ on a temporary : ideone.com/cv9oI*. That does not say that you find *temporary* misleading, but that you think that the answer is wrong because by transforming the problem into *call a member function* you can call a member function on a temporary. Again, using that code does not even hint that you are talking about the difference of *temporary* and *rvalue*, in both cases the objects are *temporaries* and the expressions are *rvalue* expressions. – David Rodríguez - dribeas Jun 03 '11 at 17:57
  • @Prasoon: That again proves that you agree that it was misleading for some people at least. I never said its misleading for all people. In fact, nothing can be misleading for all people. Its always for some people. – Nawaz Jun 03 '11 at 18:00
  • @Nawaz : The reason for the downvote didn't make sense to me at all. You **generally** pick up a point and don't even think of agreeing to what others say(even if you are wrong). – Prasoon Saurav Jun 03 '11 at 18:03
  • @David: I find *temporary* misleading, after all the answer says I cannot apply `++` on a temporary, which is wrong, as far I know. – Nawaz Jun 03 '11 at 18:04
  • @Nawaz : The context was completely different. Where in the opening post do you see used defined types being used? – Prasoon Saurav Jun 03 '11 at 18:04
  • @Prasoon: It didn't have to make sense to you. It makes sense to me. I gave my reason. – Nawaz Jun 03 '11 at 18:05
  • @Prasoon: But its not clear from your answer that it is true for this context ONLY. People usually learn concept from one example, and try to apply that in other example. That is how we learn new thing. – Nawaz Jun 03 '11 at 18:08
  • @Nawaz : It doesn't have to be clear to you. Its clear to others. :P – Prasoon Saurav Jun 03 '11 at 18:09
  • 2
    @Nawaz: seriously, a broken clock gives the right time twice a day. The answer is (and the first version of it was) quite clear. It uses the `-i` expression, that yields a *temporary* of type `int`, and an *rvalue* and it also says that `++` requires an *lvalue*. While it could be better --it could avoid mentioning temporary, it could specify that `++` requires an *lvalue unless it is overridden as class member function*, that is out of the scope of the question. It could be better, but it is not *wrong* by any means. – David Rodríguez - dribeas Jun 03 '11 at 18:11
  • @David: The term `wrong` could be wrong here :P, but all I meant is that I could very well apply `++` on temporary, but the answer says something else. So the answer was supposed to contain few more words to make it clear that its true in such and such context only. Otherwise aggressive learners like me often learn concepts from one example and try to apply it in other examples; that is how most human learns new things. As some wise man has said `Examples are the school of Mankind, they will learn at no others.` :-) – Nawaz Jun 03 '11 at 18:20
  • @Nawaz: if you want preciseness, start applying that to your comments: *I could very well apply `++` **overloaded as a member function in a user defined type** on a temporary*. The question deals with `int`, that is not a user defined type, and it is not asking whether under some complex dark circumstance it can be applied. If you want 100% precission, apply it to yourself. The comment by @Xaade applying a built in `++` to a temporary is welcomed. By your own rule of thumb, your comment is not welcomed, as it seems to indicate that `++` on ints and as member functions are *equivalent*. – David Rodríguez - dribeas Jun 03 '11 at 18:29
  • @David: Yes. But only after knowing the difference we know the difference. There is no way to know the difference, without knowing the difference. You got what I said? :| – Nawaz Jun 03 '11 at 18:34
  • You guys are crazy. 1. You cannot increment an rvalue because it doesn't have an identity. 2. You can increment an lvalue because it does have an identity. 3. Having the ++ operator override on an object allows you to call a method in an object even if it's an rvalue, but that method does not increment, the programmer may have that method implement the effects of an increment. – Lee Louviere Jun 03 '11 at 19:37
  • 1
    This comment thread seems like a lot of effort for something that could simply be written in a clearer, more understandable way (that actually works). – Robert Harvey Jun 03 '11 at 22:46
  • @Robert You mean like mine down below. – Lee Louviere Jun 14 '11 at 20:26
5

The ++ operator increments a variable. (Or, to be more precise, an lvalue—something that can appear on the left side of an assignment expression)

(-i) isn't a variable, so it doesn't make sense to increment it.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • I find the similarity of *variable* and *lvalue* much better than alternative *can appear on the left side of an assignment expression*. I have seen many people arguing that you cannot have an expression that yields a *constant lvalue* because that cannot be used as the left hand side of an assignment (Given `const int& foo();`, `foo();` is an lvalue expression, and yet you are not allowed --for other reasons-- to assign to it) – David Rodríguez - dribeas Jun 03 '11 at 17:33
1

You can't increment a temporary that doesn't have an identity. You need to store that in something to increment it. You can think of an l-value as something that can appear on the left side of an expression, but in eventually you'll need to think of it in terms of something that has an identity but cannot be moved (C++0x terminology). Meaning that it has an identity, a reference, refers to an object, something you'd like to keep.

(-i) has NO identity, so there's nothing to refer to it. With nothing to refer to it there's no way to store something in it. You can't refer to (-i), therefore, you can't increment it.

try i = -i + 1

#include <stdio.h>

int main()
{
   int i = 10;
   printf("%d\n", -i + 1); // <-- No Error Here
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Lee Louviere
  • 5,162
  • 30
  • 54
0

Try this instead:

#include <stdio.h>

int main()
{
   int i = 10;
   printf("%d\n", (++i) * -1);
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Localghost
  • 714
  • 3
  • 7