Rvalue references in a conditional expression

c++, c++11, clang, decltype, gcc

Solution

Clang is right. N3337 §7.1.6.2/4:

The type denoted by `decltype(e)` is defined as follows:

- if `e` is an unparenthesized id-expression or an unparenthesized class member access, `decltype(e)` is the type of the entity named by `e`. If there is no such entity, or if `e` names a set of overloaded functions, the program is ill-formed;

- otherwise, if `e` is an xvalue, `decltype(e)` is `T&&`, where `T` is the type of `e`;

- otherwise, if `e` is an lvalue, `decltype(e)` is `T&`, where `T` is the type of `e`;

- otherwise, `decltype(e)` is the type of `e`.

The operand of the `decltype` specifier is an unevaluated operand.

§5/6:

[ Note: An expression is an xvalue if it is:

- the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type,

- a cast to an rvalue reference to object type,

- a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or

- a `.*` pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.

In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not. —end note ]

I was wary earlier that a literal `0` may somehow prevent this from qualifying as an object type in this context, but §3.9/8 clarifies things:

An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not a void type.

The conditional operator doesn't affect anything here – §5.16/4:

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.

In this case both are of the same value category (xvalue), and xvalues are glvalues.

Problem

``` typedef decltype(true ? (long&&)0 : (long&&)0) T; ``` What should T be? According to gcc (4.7), it's `long`. According to clang (trunk), it's `long&&`. This difference is causing clang to fail to compile code that uses gcc 4.7's libstdc++. Who is right? UPDATE: As ildjarn points out, Clang is right, and as Richard Smith points out, the error libstdc++ is due to an error in the Standard. Here is the relevant GCC bug, and the relevant Defect Report.

Original source