Let there be some code in which the user-defined type S is defined by the class, in which the addition and postfix increment operations are implemented:

#include <iostream> class S { public: S(int v = 0) : val(v) {} int GetVal() { return val; } S operator++(int) { S temp = *this; ++val; return temp; } S operator+(const S& obj) { return S(val+obj.val); } private: int val; }; 

Further, there are several overloaded variants of the f() function that output to the stream information about which of them was called.

 void f(S&) { std::cout << "f(S&)\n"; } void f(S&&) { std::cout << "f(S&&)\n"; } void f(int&) { std::cout << "f(int&)\n"; } void f(int&&) { std::cout << "f(int&&)\n"; } 

Code in which all this is used:

 int main() { S s(0); int i(0); f(s); // ОК: выведет "f(S&)" f(i); // ОК: выведет "f(int&)" f(S(0)); // ОК: выведет "f(S&&)" f(int(0)); // ОК: выведет "f(int&&)" f(S(1) + S(1)); // ОК: выведет "f(S&&)" f(int(1) + int(1)); // ОК: выведет "f(int&&)" s++++; // OK i++++; // ошибка: lvalue required as increment operand S(0)++; // OK int(0)++; // ошибка: lvalue required as increment operand S(1) + S(1) = s; //OK int(1) + int(1) = i; // ошибка: lvalue required as left operand of assignment return 0; } 

The places of interest in the code are commented.

  1. Question: why for the fundamental types (in this case, int ) such operations as assignment and increment are not allowed for temporary objects of r-value type, and for user objects, for example, class S are allowed?

  2. Indeed, as a result of adding two objects (or after a postfix increment) we get a temporary rvalue-object, which does not exist outside the expression in which it appears. Where exactly can you find clarification on this?

  3. What are some ways to prohibit this behavior for custom types? Use in the method declaration reference qualifiers & and &&, such as:

S operator++(int) & ?

  • If you are given an exhaustive answer, mark it as correct (a daw opposite the selected answer). - Nicolas Chabanovsky

2 answers 2

I answer the first and second questions; the third you yourself answered. It's very simple: Standard C ++ [basic.lval] p5

It can be used to modify the referee under certain circumstances. [Example: a function can be called an object (9.3) can modify the object. - end example]

Those. it is impossible to apply a modifying operation to an rvalue expression, unless the result of an expression is an object of a class, the modifying operation is its method (member function). Although part of the passage above is very vague: "under certain circumstances" and no explanation about these "circumstances"

    Well, you didn't say that increment is only allowed for lvalue?

    Try this increment:

     S operator++(int) & { S temp = *this; ++val; return temp; } 

    Similarly with assignment.

    However, you yourself have already answered this question :)

    • I just wanted to know where you can read about it in detail (the answer to the first question). Any specific source, so as not to interrupt everything - Dmitry
    • Yes, frankly, you are not surprised by f(S(0)); ? And how, in principle, does this call differ from S(0)++ ? Also a function call, only with a very specific name. There are rather restrictions on int - because they have no effect. Honestly, I find it difficult to give a link to a particular place .. - Harry
    • one
      Clear. Apparently due to the possibility of operator overloading for user types, such manipulations with temporary r-value objects are allowed. Even such seemingly pointless operations as assigning a value to a temporary object can make sense in a specific case, if this meaning is realized through overloads. - Dmitriy