4

Whilst learning about value categories, I found that the following snippet compiled and run just fine:

#include <iostream>

int main() {
    int x = 1;
    int y = 2;
    (true ? x : y) = 4;
    std::cout << x << std::endl;
}

Here's the output:

4

First, I checked whether this statement was legal C++, and I believe it is because of the following:

N4296 5.16.4 Conditional operator [expr.cond]

If the second and third operands are glvalues of the same value category and have the same type, the result is of that type and value category and it is a bit-field if the second or the third operand is a bit-field, or if both are bit-fields.

Given that both x and y are lvalues (and therefore glvalues), the result of the conditional expression in both cases is an lvalue. On this basis, the expression seems valid. However what's not clear is whether this should have any effect.

The reason I am not sure whether the conditional statements should have an effect is because the type of the second and third operand type is int. Even if this result int is an lvalue, that doesn't meant it has to refer to x or y. It could essentially be a dummy variable, leading to no effect, and be standard conforming. In other words, I see no reason for it to resolve to an int& rather than a separate int.

My question is...

Is this behaviour correct and why?


I took a look at this question beforehand, but don't believe it answers my question. The answers to this question refer to an older standard, with different wording, and don't answer my question about whether the result is an int& to x or not.

OMGtechy
  • 7,935
  • 8
  • 48
  • 83
  • 3
    I don't get it. in `(x > y ? x : y)` `x` is not grater than `y` so `y` is the result but you print `x` expecting it to be changed. – NathanOliver Mar 22 '17 at 17:37
  • @NathanOliver doh, you're right, I'll edit the question – OMGtechy Mar 22 '17 at 17:39
  • @WhozCraig editted, my question is has reduced to "why is this the case" now, because I can't see why it'd act like an `int&` rather than just assigning to some dummy variable. – OMGtechy Mar 22 '17 at 17:42
  • Well, the behaviour you're seeing is certainly correct. Each term (`x` and `y`) are glvalues of the same value category (in this case lvalue) and type (in this case `int`), so the result of the expression per the standard you cited should be an lvalue `int`. So the root of your question is why this is not treated as an xvalue? Is that right? Isn't the answer to that exactly what you cited? *"...the result is of that type and value category ..."* – WhozCraig Mar 22 '17 at 17:46
  • @WhozCraig Rather, I think OMG is asking "is there a guarantee in the standard that the lvalue that `true?x:y` returns is `x` and not some anonymous lvalue conjured out of thin air, whose value happens to be the same as `x`". OMG, this may(?) vary from one version of C++ to another; can you be specific about what version(s) of C++ you are asking about? – Yakk - Adam Nevraumont Mar 22 '17 at 19:48
  • @Yakk yes, that is what I mean. I'd be interested to know how it changed over time, but I'm most interested in the latest standard (which is C++14 at the time of writing). – OMGtechy Mar 22 '17 at 22:20
  • FYI: In C "a conditional expression does not yield an lvalue". Hence, GCC (for example) produces "error: lvalue required as left operand of assignment". – pmor Dec 21 '22 at 09:46

1 Answers1

0

The description of the conditional operator begins with something like this. I am quoting from the latest working draft, but the meaning has been the same in all standard versions, with some minor improvements in wording over time:

Conditional expressions group right-to-left. The first expression is contextually converted to bool (7.3). It is evaluated and if it is true, the result of the conditional expression is the value of the second expression, otherwise that of the third expression. Only one of the second and third expressions is evaluated. The first expression is sequenced before the second or third expression (6.9.1).

That is [expr.cond]/1. The remainder of [expr.cond] explains how to determine the type and value category of the conditional expression and what conversions must be applied, if any. Those parts will not repeat the fact that the result is the second or third operand, because it has already been stated up front. So, when both the second and third operands are lvalues of type int, the result can only be an lvalue referring to either the second or third operand, because any other result would not be consistent with the first paragraph.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312