Topic: C++0x: conditional operator, xvalues, and decltype


Author: SG <s.gesemann@gmail.com>
Date: Mon, 11 Oct 2010 14:06:16 CST
Raw View
Hello!

With my current interpretation of draft N3126 w.r.t. the conditional
operator and xvalues, I expect the following assertions to hold:

 int i = 0;
 int& j = true? i : i;
 int&& k = true? std::move(i) : std::move(i);   // #2
 assert(&i == &j); // Holds since C++98
 assert(&i == &k); // Should this hold as well?

5.16/4 says:

 If the second and third operands [to the conditional operator] are
 glvalues of the same value category and have the same type, the
 result is of that type and value category [...]

Though, it doesn't clearly say that the resulting glvalue refers to
one of the objects the glvalue operands referred to -- or is this
implied because otherwise it would return a prvalue? Using GCC 4.5.1
in C++0x mode the second assertion fails. The reference k seems to
refer to some temporary object. Can somebody clarify whether the
comiler is allowed to create such a temporary in case both operands
around the colon are xvalues of the same type?

I'm currently assuming GCC is buggy and/or not up-to-date with respect
to xvalues.

The followup question is: Wouldn't it be nice to be able to detect the
value category of an expression? If we ignore the conditional operator
we can detect the value category of an expression with decltype. But
what is

 bool xvalue = std::is_rvalue_reference<
   decltype( true ? std::move(i) : std::move(i) ) >::value;

supposed to yield? Using GCC 4.5.1, the xvalue variable is initialized
with false. Is this conforming to the current standard draft?

TIA,
Sebastian

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =?ISO-8859-1?Q?Daniel_Kr=FCgler?= <daniel.kruegler@googlemail.com>
Date: Fri, 22 Oct 2010 16:44:46 CST
Raw View
[To the mods: I did two reply attempts over three or four days, but
did neither get a confirmation message nor any successful reply
occurrence in the group. This time I did not use the Google account ;-)
Should my previous postings be found: This one should be considered
as a replacement of the other two]

[ We've had (more) server troubles, and have been moving the
moderation queues.  comp.lang.c++.moderated also.  -- mod/jad ]

Am 11.10.2010 22:06, schrieb SG:
> With my current interpretation of draft N3126 w.r.t. the conditional
> operator and xvalues, I expect the following assertions to hold:
>
>   int i = 0;
>   int&  j = true? i : i;
>   int&&  k = true? std::move(i) : std::move(i);   // #2
>   assert(&i ==&j); // Holds since C++98
>   assert(&i ==&k); // Should this hold as well?
>
> 5.16/4 says:
>
>   If the second and third operands [to the conditional operator] are
>   glvalues of the same value category and have the same type, the
>   result is of that type and value category [...]
>
> Though, it doesn't clearly say that the resulting glvalue refers to
> one of the objects the glvalue operands referred to -- or is this
> implied because otherwise it would return a prvalue?

This is a bit tricky: There are two positions to consider. First we have
the initializer expression involving the conditional operator

   true? std::move(i) : std::move(i)

Here we have a similar situation for xvalues as we have for lvalues (which
also don't mention explicitly that the result will refer to the
original referee).
3.10/2 clearly says that every xvalue refers to an object, analogously to
object lvalues. And 5.16 is very clear when temporaries are produced, none
of them applies here.

Second, we have an rvalue-reference k initialized with above expression.
As of the working paper (8.5.3 p.5 b.2 sb.4) a temporary will be produced
during the initialization of k:

"    Otherwise, a temporary of type    cv1 T1    is created and initialized from
the initializer expression using the rules for a non-reference copy-
initialization (8.5).
      [..]
In all cases except the last (i.e., creating and initializing a temporary from
the initializer expression), the reference is said to bind directly to the
initializer expression."

This will change, when

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1138

would be applied. In this case the compiler is no longer allowed to create
any temporary here when we fall in the bucket 8.5.3 p.5 b.2 sb.1 ssb.1.

Note that

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1139

discusses the very same problem that you are referring to.

> Using GCC 4.5.1
> in C++0x mode the second assertion fails. The reference k seems to
> refer to some temporary object. Can somebody clarify whether the
> comiler is allowed to create such a temporary in case both operands
> around the colon are xvalues of the same type?

The compiler does it correctly according to the current WP, but will
no longer be allowed to do that when the proposed resolution of #1138
is applied. A recent gcc trunk does already follow this 1138 P/R.

> The followup question is: Wouldn't it be nice to be able to detect the
> value category of an expression? If we ignore the conditional operator
> we can detect the value category of an expression with decltype. But
> what is
>
>   bool xvalue = std::is_rvalue_reference<
>     decltype( true ? std::move(i) : std::move(i) )>::value;
>
> supposed to yield? Using GCC 4.5.1, the xvalue variable is initialized
> with false. Is this conforming to the current standard draft?

Yes, unfortunately this is conforming. This time the problem is located
in the definition of decltype. We fall into 7.1.6.2 p.4 b.4 for the expression
shown above and the result is just int.

Personally I consider this as an unsatisfactory state, unnecessarily
inconsistent to the handling of lvalues (which would fall in bullet 3). To
me the best way of resolving this inconsistency would be to change
bullet 3 to a proper "glvalues" bullet:

    otherwise, if e is an <ins>g</ins>lvalue, decltype(e) is T& <ins>for an
lvalue and is T&& for an xvalue</ins>, where T is the type of e;

HTH & Greetings from Bremen,

Daniel Kr   gler

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]