views:

133

answers:

1

I am reposting a comp.std.c++ Usenet discussion here because that group has become very unreliable. The last few posts I've submitted there have gone into the void, and activity has all but ceased. I doubt I've been banned and/or everyone else just lost interest. Hopefully all interested people will find this discussion, and there will be a general migration. Maybe then they will appoint a new moderator.


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

+2  A: 

I think GCC 4.5.1 is nonconforming wrt §5.16/4. Have you filed a bug report?

Anyway, I think it is conforming with that ternary operator code. decltype is defined by §7.1.6.2/4:

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

  • if e is an unparenthesized id-expression or a class member access (5.2.5), 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 a function call (5.2.2) or an invocation of an overloaded operator (parentheses around e are ignored), decltype(e) is the return type of the statically chosen function;
  • 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 (Clause 5).

decltype works by fetching the appropriate declaration and returning the desired type from it. It has little intelligence with respect to non-overloaded operators. Perhaps another point

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

would be in order, particularly since, as written, xvalues get treated as prvalues. Furthermore, your expression corresponds exactly to the definition of std::common_type (§20.7.6.6/3).

One straightforward workaround (to coin a phrase :vP ):

template< typename T1, typename T2 >
struct common_type_and_category {
    typedef typename std::conditional<
        std::is_same< T1, T2 >::value,
        T1,
        typename std::common_type< T1, T2 >::type
    >::type type;
};
Potatoswatter