Am 06.05.2013 18:38, schrieb Daryle Walker:
> template < typename T, std::size_t N >
> auto f( T (&x)[N] ) -> T &
> { return Whatever ? throw nullptr : x[0]; }
>
> This is like one of those exercises with code using std::vector<T>
> that chokes when T is bool due to the vector<bool> having simulated
> references instead of real ones. In my case, having exactly one
> action of a conditional be void (like a throw expression) gives the
> conditional the type of the other action. However, it's actually the
> other action's type AFTER decay. So array-reference returns become
> pointers, which messes up your plans (like if "x" was a nested array).
Note that the reason here is not directly related to the fact that
array-to-pointer conversion is happening. The actual reason is the
specification of the conditional operator, which has the following
special case in [expr.cond] p2 b1:
"� The second or the third operand (but not both) is a throw-expression
(15.1); the result is of the type of the other and is a prvalue."
Essentially this wording has caused a core language issue
www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1550
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1560
The proposed resolution was accepted during the previous Bristol
meeting, so in the future your original code will be well-formed.
> The way around it is to force the void action to be a non-void one,
> preferably of the same type as the other action:
>
> template < typename T, std::size_t N >
> auto f( T (&x)[N] ) -> T &
> { return Whatever ? throw nullptr, ZZZ : x[0]; }
Yes, this works, because the type and value category of the comma
expression corresponds to that of the second operand, see [expr.comma] p1:
"The type and value of the result are the type and value of the right
operand; the result is of the same value category as its right operand,
and is a bit-field if its right operand is a glvalue and a bit-field. If
the value of the right operand is a temporary (12.2), the result is that
temporary."
> The easiest way to get "ZZZ" to have the same type as the other action
> is to repeat the other action ("x[0]" here). I used a macro. That
> extra copy doesn't get evaluated since the throw happens first; the
> copy is there only to change the return type of the first action.
Let me add that this problem was also quite annoying for constexpr
functions, which are quite restricted in C++11 (but no longer in C++14).
> Can we get rid of the decay rule here, or otherwise, to fix this?
We just got rid of that one ;-)
HTH & Greetings from Bremen,
Daniel Kr�gler