1

I have a custom class MyInt, encapsulating a int m_nValue data. The postfix operator

MyInt operator++(int)  
{
  MyInt temp(*this);  
  ++(*this);  
  return temp; 
}

if the operator returns an object, then why i am not able to call postfix++ operator more than once like:

MyInt value(10);
value++;    // valid
value++++;  // Why is this invalid?? Cant it be interpreted as (value++)++

Why does value++++ gives an error lvalue required if i can call value.print() method defined in MyInt Class, then i should also be able to do value++++?

Abhinav
  • 1,496
  • 3
  • 15
  • 31
  • With `int x`, `x++` also returns an `int` ;) –  Oct 18 '11 at 12:52
  • @delnan yes i have tried that too. but as i can call methods on the returned value, i was thinking i can use a ++ again just like a method. What makes the postfix operator different that i can call a method on the returned value but i cant use postfix ++ more than once? – Abhinav Oct 18 '11 at 12:57
  • I guess the real question is why the postfix increment requires an lvalue... – Kerrek SB Oct 18 '11 at 12:58
  • @KerrekSB yes the question can also be interpreted like that. Why different behaviors of post and pre? – Abhinav Oct 18 '11 at 13:03
  • This looks like a compiler bug. What version are you using? – R. Martinho Fernandes Oct 18 '11 at 13:11
  • Which visual-c++ are you using? Older visual-c++ (for example vc++6) did not conform to the standard. – Shahbaz Oct 18 '11 at 13:44
  • Looks indeed like a bug. `x++++` compiles fine in GCC 4.6.1. Note of course that under the standard semantics, `x++` and `x++++` and `x++++++` all result in the same final value of `x`. – Kerrek SB Oct 18 '11 at 14:09
  • i am using g++4.2.1, darwin/MacOSX SL Shipped with the SDK – Abhinav Oct 18 '11 at 17:00

2 Answers2

5

Wrong answer:

Because value++ is a temporary variable that holds the old value of value. You can't ++ it.

You also can't write 15++! It's similar. The former is a temporary variable, the later is a constant, none of which you can increment.

Correction: Since this answer got accepted, I am not going to change the original post, but since people will read it, I will post the correction here.

First off, I am not saying constants and temporary objects are the same concept. I was just trying to say temporary objects are not l-values, like constants are not, without actually using the word l-value.

About value++++, it is not an error. I just tested it with my g++ 4.5 and it works fine. In other answers you can read:

From section 3.10.10 of the 2003 standard:

An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]

What is inherently wrong about what you are doing is this:

Let's say value holds 10. The first value++ changes value to 11 but returns a temporary object containing 10. Then you ++ it which changes the temporary value (that you never access) to 11, but again returns a temporary object that contains 10. So value++++ behaves exactly like value++ except it does some unnecessary work.

Community
  • 1
  • 1
Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • I am imagining a world where people would write value+++++++++++. The horror! – Kajetan Abt Oct 18 '11 at 12:53
  • Yes because when you write `++value`, you change the variable `value` itself, and return a reference to it. Then, it's not a temporary variable. If you don't return a reference, then `++++++++++++value` is also not possible. – Shahbaz Oct 18 '11 at 12:59
  • 6
    This actually not correct. You can call member-functions on rvalues just fine. gcc 4.3.4 [agrees here](http://ideone.com/OMYxr). – Björn Pollex Oct 18 '11 at 13:00
  • @Kdansky may be the shorthand notation or utility operators are Horror for you. you may be horribly using them or you have bad aesthetic sense. But to many people this is a beauty. – Abhinav Oct 18 '11 at 13:00
  • @BjörnPollex, can you explain what you mean? What member function? – Shahbaz Oct 18 '11 at 13:01
  • I'm fine with ++value, but ++++++++++++value is just worse style than value += 6. – Kajetan Abt Oct 18 '11 at 13:02
  • @Shahbaz: `operator++(int)` is (and always must be) implemented as a member-function (of `MyInt`) in this case. – Björn Pollex Oct 18 '11 at 13:02
  • 7
    ***This is not the correct answer.*** You certainly can `++` temporaries of user-defined types. `15++` is *similar*, but only syntactically. It's not at all the same thing as calling `operator++(0)` on a UDT. A previous question about UB shows [an example](http://stackoverflow.com/questions/4638364) of a significant difference. This question shows another example of a difference. And a constant and a temporary are completely different things. – R. Martinho Fernandes Oct 18 '11 at 13:28
  • @R.MartinhoFernandes, I know, they are different. They are however similar in this sense where none of them are supposed to be changed (they are not l-value). For example, you cannot write `a++ = 10;`, neither `11 = 10;`. I meant similar so that I could very simply explain what is not an l-value. – Shahbaz Oct 18 '11 at 13:32
  • @Shahbaz: not being an l-value does not prevent calling `operator++(0)` on it. – R. Martinho Fernandes Oct 18 '11 at 13:33
  • On second thought, this could have been (but isn't, of course) one of those situations where the expression and the function are different things. So `x++++` as an expression could have been forbidden, while `x.operator++(0).operator++(0);` could have been allowed. This is ultimately not how the standard turned out to be, though, and it's probably for the better, since it allows greater flexibility for the use of the postfix-`++` (which may well have entirely different semantics in user-defined types). – Kerrek SB Oct 18 '11 at 14:13
4

Actually, this should work:

#include <iostream>

struct MyInt {
    MyInt() : value(0) {}

    MyInt& operator++() {
        std::cout << "Inside MyInt::operator++()" << std::endl;
        ++value;
        return *this;
    }

    MyInt operator++(int)  
    {
      MyInt temp(*this);  
      ++(*this);  
      return temp; 
    }

    int value;
};

int main() {
    MyInt mi;

    std::cout << "Value before: " << mi.value << std::endl;
    mi++++;
    std::cout << "Value after: " << mi.value << std::endl;
}

This operator is basically just a normal member-function with fancy syntax, and as such you can invoke it on an rvalue. Note how, as Martinho explains in his comment, the effect is not the desired one, because the second increment operates on a temporary.

From section 3.10.10 of the 2003 standard:

An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • 4
    I'd like to note that while it should work, it also should not work. Id est, it should compile, but it should not increment `value` twice. (It increments `value` once, and then increments the temporary that results from `value.operator++(0)`. The end result is the same as `value++`). – R. Martinho Fernandes Oct 18 '11 at 13:12
  • 1
    @ptr_user7813604 Yeah, I should have pasted the original code here. I've created a new example and added the code inline here. – Björn Pollex Nov 22 '18 at 07:16