17

PREMISE:

The C++11 Standard classifies expressions into three disjoint value categories: lvalues, xvalues, and prvalues (§ 3.10/1). An explanation of what value categories are is available for instance here.

I am struggling to figure out what are the requirements of the different operators on the value category of their operands. Paragraph 3.10/1 specifies:

[...] Every expression belongs to exactly one of the fundamental classifications in this taxonomy: lvalue, xvalue, or prvalue. This property of an expression is called its value category. [ Note: The discussion of each built-in operator in Clause 5 indicates the category of the value it yields and the value categories of the operands it expects. For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return types. —end note ]

In spite of what the note above claims, Clause 5 is not always very clear about the value category of operators' operands. This is, for instance, all that is said about the value category of the operands of the assignment operator (Paragraph 5.17/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. The result in all cases is a bit-field if the left operand is a bit-field. 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. With respect to an indeterminately-sequenced function call, the operation of a compound assignment is a single evaluation. [ Note: Therefore, a function call shall not intervene between the lvalue-to-rvalue conversion and the side effect associated with any single compound assignment operator. —end note ]

How about the right operands?

The words "rvalue" and "lvalue" no more occur in the whole Section 5.17. While the note in Paragraph 3.10/1 makes it explicit that the built-in assignment operators expect a prvalue as a right operand, this is not explicitly mentioned in Section 5.17. Even the final note of 5.17/1, which mentions lvalue-to-rvalue conversions, seems to imply that rvalues are expected somehow (what's the need for a conversion otherwise?), but notes are non-normative after all.

Sections concerning other operators, including multiplicative and additive operators, are generally silent on the value category of their operands. I couldn't find any "default statement" in the Standard stating that, when not specified otherwise, the operands of built-in operators are rvalues. Hence, the question.

QUESTION:

  1. What is the value category of the right operand of the assignment operator; and, more generally
  2. How to figure out the value category of an operator's operand when this is is not specified? Is it unconstrained (meaning that any value category is accepted)? If so, why should lvalue-to-rvalue conversions ever apply in an assignment expression?

References to the C++11 Standard are highly appreciated.

Community
  • 1
  • 1
Andy Prowl
  • 114,596
  • 21
  • 355
  • 432
  • The value category of the Right hand side is whatever the function parameter expects (I think `&&` are prvalues, `&` are lvalues, `const&` are anything, and values are anything). For all primitive types, we can infer the signature is `T& operator=(const T&rhs)`, but I don't think it is explicitly stated anywhere. – Mooing Duck Feb 20 '13 at 22:43
  • Heh, the note says that "Clause 5 indicates" and not "Clause 5 defines" :) The indication for assignment is 5.17p2 "In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand." – Johannes Schaub - litb Feb 20 '13 at 22:50
  • @JohannesSchaub-litb: Do you know what's the intended specification? Provided it's ill-defined, are we meant to assume that right operands of built-in operators are rvalues when unspecified? – Andy Prowl Feb 20 '13 at 22:51
  • @MooingDuck: Why so? For primitive types, it could equally well be `T& operator=(T)` I believe. No? – Andy Prowl Feb 20 '13 at 22:53
  • @AndyProwl unfortunately, I don't think there is anything conclusive to say. I think the spec is ill-specified and leaves out the promised "discussion of each built-in operator" :) – Johannes Schaub - litb Feb 20 '13 at 22:54
  • Congrats on the 10k! Is this your first account on SO? You seem to be really good.:) – 0x499602D2 Feb 20 '13 at 22:57
  • @JohannesSchaub-litb: Shall I then conclude, that an answer to [this question](http://stackoverflow.com/questions/14935722/does-initialization-entail-lvalue-to-rvalue-conversion-is-int-x-x-ub) cannot be given either? Without a clear list of what value categories are expected for each language construct, it's hard to figure out when an lvalue-to-rvalue conversion is needed. – Andy Prowl Feb 20 '13 at 22:57
  • @David: Thank you, but you are celebrating me more than I deserve :-) Yes, this is my first account. – Andy Prowl Feb 20 '13 at 22:58
  • @AndyProwl The note at 4p8 has interesting phrasing: "There are some contexts where certain conversions are suppressed. For example, the lvalue-to-rvalue conversion is not done on the operand of the unary & operator. Specific exceptions are given in the descriptions of those operators and contexts.". This sounds like the guy writing that note thought that the lvalue to rvalue conversion is always done on all operands of built-in operators, except when otherwise noted. – Johannes Schaub - litb Feb 20 '13 at 23:01
  • Perhaps the search ends in the C Standard, because in the C Standard an lvalue to rvalue conversion *is* done by default, and the few exceptions are listed at a single place. – Johannes Schaub - litb Feb 20 '13 at 23:02
  • @JohannesSchaub-litb: Brilliant. This sheds some more light on the intended specification, at least – Andy Prowl Feb 20 '13 at 23:03
  • @MooingDuck When an operator is transformed into a function call because it has been overloaded, the rules from section 5 don't apply. (Pointed out in Note §5/2 and then in the following paragraph: "Clause 5 defines the effects of operators when applied to types for which they have not been overloaded.") – Joseph Mansfield Feb 20 '13 at 23:25
  • sftrabbit you tricked me into thinking I made a mistake and deleting my comment! :D We're talking about the _effective_ prototypes, there's no actual overloading or functions happening. @AndyProwl it could be that format, but then the expected type of the rhs would be whatever the constructor expects. As primitives aren't usefully movable, the only effective constructor prototype would be `T(const T&)`, which is the same RHS and value category as the assignment I suggested. – Mooing Duck Feb 20 '13 at 23:50
  • @MooingDuck: Primitive types don't have constructors though. I don't think reasoning in terms of constructors for primitive types is a correct approach here – Andy Prowl Feb 20 '13 at 23:52
  • @MooingDuck Apologies! - I can't remember exactly what your comment said any more but I don't think I was trying to say it was wrong, just giving more information! – Joseph Mansfield Feb 21 '13 at 14:17
  • @AndyProwl I've posted a [defect report](https://groups.google.com/a/isocpp.org/d/topic/std-discussion/zhe10OxlEZk/discussion) in the standard discussion group. Please add anything you think is relevant! – Joseph Mansfield Mar 15 '13 at 16:15
  • @sftrabbit: Seems like your description is pretty much complete, if I'll feel anything deserves being added, I will post a message :) Thank you for notifying me! – Andy Prowl Mar 15 '13 at 16:29
  • @sftrabbit any updates on that defect report? I ask this question: [Does the standard mandate that lvalue-to-rvalue conversion of the pointer variable when applying indirection?](http://stackoverflow.com/questions/21053273/does-the-standard-mandate-that-lvalue-to-rvalue-conversion-of-the-pointer-variab) question and I was pointed to this thread and the answer to that defect report should also answer my question too. – Shafik Yaghmour Jan 11 '14 at 04:05

1 Answers1

7

Yes, it's ill-specified and has been covered before. Basically, every time an lvalue expression is required is enumerated, so we assume that every other operand must be a prvalue expression.

So to answer your questions:

  1. A prvalue.
  2. If it's not specified, it's a prvalue.

The note that is quoted in the linked answer seems to have changed a few times. The quote from §3.10 of the C++11 standard is as follows (and at the current time is identical in the latest draft):

[ Note: The discussion of each built-in operator in Clause 5 indicates the category of the value it yields and the value categories of the operands it expects. For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return types. — end note ]

Here it even says explicitly that the assignment operators expect the right operand to be a prvalue. Of course, this is a note and is therefore non-normative.

Community
  • 1
  • 1
Joseph Mansfield
  • 100,738
  • 18
  • 225
  • 303
  • I can't find in my draft of the Standard the wording that is alleged to be part of 3.10 by the answer you linked. Is the n3485 draft different anyhow? I do not have the original Standard. For instance "*[Example: the unary and binary + operators expect rvalue arguments and yield rvalue results. — end example ]*" is missing. Also, if it is unspecified, why can we "assume that every other operand must be a prvalue expression"? – Andy Prowl Feb 20 '13 at 22:46
  • @AndyProwl I agree that it's silly that we have to assume something that is not specified but unfortunately it's just not very well defined. It is something that the compiler developers have essentially agreed on. Logicially, an operand is a prvalue if the operation requires using the value of that operand. I'm currently looking into if there is an issue reported for it. – Joseph Mansfield Feb 20 '13 at 22:59
  • Thank you, your answer basically confirms what I was suspecting, although I was hoping it was just an oversight of mine. +1, and will accept in a few hours if no more convincing answers are given. – Andy Prowl Feb 20 '13 at 23:01
  • @AndyProwl I've had a quick search of the issues lists and can't find anything, unfortunately. – Joseph Mansfield Feb 20 '13 at 23:07