Cv-qualifications of prvalues (revisited)
This is a followup to my previous question, where the apparent consensus was that the change in treatment of cv-qualifications of prvalues was just a fairly minor and inconsequential change intended to solve some inconsistencies (e.g. functions returning prvalues and declared with cv-qualified return types).
However, I see another place in the standard that appears to rely on prvalues having cv-qualified types: initialization of const
references with prvalues through temporary materialization conversion. The relevant wording can be found in multiple spots in 9.3.3/5
[...] If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion ([conv.rval]) is applied [...]
[...] Otherwise, the initializer expression is implicitly converted to a prvalue of type “cv1 T1”. The temporary materialization conversion is applied and the reference is bound to the result.
The intent is obviously to make sure that when we get to the actual temporary materialization conversion
7.3.4 Temporary materialization conversion
1 A prvalue of type T can be converted to an xvalue of type T. This conversion initializes a temporary object ([class.temporary]) of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object. [...]
the type T
that it receives as input includes the required cv-qualifications.
But how does that cv-qualification survive the 7.2.2/2 in case of non-class non-array prvalue?
7.2.2 Type
2 If a prvalue initially has the type “cv T”, where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis.
Or does it?
E.g. what kind of temporary do we get in this example
const int &r = 42;
Is the temporary const
or not? Can we do
const_cast<int &>(r) = 101; // Undefined or not?
without triggering undefined behavior? If I'm not mistaken, the original intent was to obtain a const int
temporary in such cases. Is it still true? (For class types the answer is clear - we get a const
temporary.)
Why are you doubting the language of 7.2.2? This seems pretty unambiguous that cv qualifiers are discarded on non-class, non-array prvalues, so the type T in temporary materialization is a non-const, non-volatile type.
If that weren't the case, then you wouldn't be able to bind prvalues to non-const rvalue references. Yet it seems overwhelmingly likely that the standard was intended to accept programs such as this:
#include <type_traits>
template<typename T> void
f(T &&t)
{
static_assert(std::is_same_v<decltype(t), int&&>);
++t;
}
int
main()
{
f(5);
}