Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cv-qualifications of prvalues in C++14

It appears that C++11 and C++14 treat cv-qualifications of prvalues differently.

C++11 sticks to the "classic" approach that has been around since C++98: according to 3.10/4 "non-class prvalues always have cv-unqualified types".

C++14 contains a similar wording in 3.10/4, but it is presented as a note: "[Note: class and array prvalues can have cv-qualified types; other prvalues always have cv-unqualified types. See Clause 5. —end note ]"

And in Clause 5 it says:

6 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.1

This 5/6 entry is new in C++14. It now treats cv-qualifications of prvalues using the same approach that has always been used with results of reference type (see 5/5).

What could be the reason for this change? C++11 and before denied non-class prvalues the right to have any cv-qualifications. C++14 says that non-class, non-array prvalues can have cv-qualifications, but these cv-qualifications are discarded prior to any further analysis.

My guess would be that there are some new (for C++14) language features that can somehow "see" cv-qualifications of prvalues under the right circumstances (before the aforementioned adjustment takes place). Do they exist? And if so, what are these features?2


The question originated from following context: imagine a compiler that internally implements hidden parameter this of class X as a variable of type X *const. Since the compiler is required to expose this as a prvalue, that const should not lead to any problems in C++11 (or before), where scalar prvalues are never cv-qualified. But what about C++14? If the very same compiler exposes that this as a prvalue of type X *const, could it possibly lead to problems?


1 There appears to be a contradiction between 5/6 and the note in 3.10/4 in C++14, but notes are not normative anyway. And I'm using a draft version of the text.

2 My initial guess was decltype. And I even thought that I found the answer when I tried

std::cout << std::is_same<decltype((const int) 0), const int>::value << std::endl;

in GCC, which outputs 1. However, seeing that Clang and VC++ output 0 (and that the spec of decltype does not seem to support this behavior) I'm inclined to believe that this is just a bug in GCC (starting from 6.1)

like image 384
AnT Avatar asked Mar 23 '17 23:03

AnT


1 Answers

According to the commit on github, this was done to resolve CWG1261: Explicit handling of cv-qualification with non-class prvalues

Based on comments to the question it seems there was room for surprising variations in type category of this (formally a prvalue) and that gcc formerly and MSVC currently instead used a const lvalue.

The wording tightens up the hole to be explicit that, e.g., even if this is by some compiler-internal magic a prvalue of type X* const, prior to any further analysis it is adjusted to X*.

Similarly, your given example does look like a gcc bug. Possibly decltype isn't looking at the value type before applying the c-style cast.

The reason it's now a note in [basic.lval]/4 is that it's now a consequence of the new text in [expr]/6, rather than specifying the rule in [basic.lval]/4.

Full credit to T.C. for having basically answered this in the comments on the question, including the reference to the gcc bug-fix, and various other examples of previously under-specified behaviours for cv-qualified non-class non-array prvalues.

like image 161
TBBle Avatar answered Nov 14 '22 02:11

TBBle