C++ Logo


Advanced search

Subject: Conditional operator with const lvalue and non-const prvalue
From: Brian Bi (bbi5291_at_[hidden])
Date: 2019-09-23 10:01:56

Consider the following:

#include <type_traits>
struct S {};
bool b;
int main() {
    const S s {};
    static_assert(std::is_same<decltype(b ? S{} : s), const S>::value);

Here <http://coliru.stacked-crooked.com/a/49d1853146cbcdc1> GCC and Clang
confirm that the type is correct. But I can't figure out why. My reading of
the standard is that the result should be a prvalue of type S, not const S.

[expr.cond]/4 applies because the two operand types are not the same (one
is S, the other is const S) but at least one is a class type. We must
therefore try to form an implicit conversion sequence in each direction. An
implicit conversion sequence cannot be formed from the prvalue operand to
const S& because (4.1) contains a restriction that the reference must bind
directly to a glvalue. In the other direction, we have the identity
conversion sequence from the const lvalue operand to S. Thus, /4 seems to
tell us that the const lvalue operand must be converted to S, and the
result should have type S.

Yet I would not expect both GCC and Clang to be wrong here, so I think that
I have misunderstood the standard in this case. Surely there must be a
reason why the result has type const S, but I can't figure it out.

(Even if we assume that the compiler is obligated to perform an
lvalue-to-rvalue conversion on the const lvalue operand, resulting in a
const prvalue, that still doesn't seem to explain the result. If this were
the case, /4 would end with a const prvalue and a non-const prvalue, /5
would not apply, and we would get to /6 and the types would still not be
the same. The "overload resolution" procedure prescribed there would fail
since S can't be converted to any scalar types, making the program
ill-formed. This interpretation thus cannot be correct either.)

*Brian Bi*

STD-DISCUSSION list run by herb.sutter at gmail.com

Older Archives on Google Groups