What does cv-unqualified mean in C++?
There are fundamental types and compound types. Fundamental types are the arithmetic types, void
, and std::nullptr_t
. Compound types are arrays, functions, pointers, references, classes, unions, enumerations, and pointers to non-static members.
A cv-unqualified type is any of those types.
For any cv-unqualified type, there are three corresponding cv-qualified types:
- const-qualified - with the
const
cv-qualifier - volatile-qualified - with the
volatile
cv-qualifier - const-volatile-qualified - with both the
const
andvolatile
cv-qualifiers
Note, however, that cv-qualifiers applied to an array type actually apply to its elements.
The cv-qualified and cv-unqualified types are distinct. That is int
is a distinct type from const int
.
What Does cv-qualified Mean?
c in cv means const and v means volatile.
From the C++ Standard (3.9.3 CV-qualifiers)
The term object type (1.8) includes the cv-qualifiers specified in the decl-specifier-seq (7.1), declarator (Clause 8), type-id (8.1), or newtype - id (5.3.4) when the object is created.
A const object is an object of type const T or a non-mutable subobject of such an object.
A volatile object is an object of type volatile T, a subobject of such an object, or a mutable subobject of a const volatile object.
A const volatile object is an object of type const volatile T, a non-mutable subobject of such an object, a const subobject of a volatile object, or a non-mutable volatile subobject of a const object.
Cv-qualifications of prvalues in C++14
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.
cv qualifiers in decltype of prvalue expression
As per the CPP standard draft n4713:
8.2.1 Value category [basic.lval]
...
9. ... Class prvalues can have cv-qualified types; non-class prvalues always have cv-unqualified types.
Since (i + j)
evaluates to a non-class prvalue, it will have a cv-unqualified type and using decltype
on it yields an int
.
What is the relevance of this statement in 7.1.6.1/1 in the C++ Standard?
Sure, most class and enum definitions make use of it:
struct A { }; // valid
const struct B { }; // invalid, const would have no meaning
const struct C { } c { }; // valid
There is nothing else. An init-declarator-list is only used in a simple-declaration, and for that, the standard (C++11) states:
7 Declarations [dcl.dcl]
3 In a simple-declaration, the optional init-declarator-list can be omitted only when declaring a class (Clause 9) or enumeration (7.2), that is, when the decl-specifier-seq contains either a class-specifier, an elaborated-type-specifier with a class-key (9.1), or an enum-specifier.
Correlation between specifier and qualifier?
Most of it doesn't make sense.
Specifier and qualifier are defined in the C++ standard. Qualifier is just an integral part of a specifier. For example, type specifier in a declaration can include cv-qualifiers. I don't see the reason to quote everything from the standard on this topic.
Cv-qualifiers are not restricted to lvalues. Rvalues of class types can also be cv-qualified. It is possible to cv-qualify an rvalue of non-class type, but it will have no effect and will be ignored.
The use of const
qualifier that you show in your example with foo
is just a syntactic form, which actually means that the const-qualifier is applied to the implied this
parameter of the foo
method: const A* this
. I.e. in this case it does indeed qualify an lvalue, but it is *this
, not foo
.
The term qualifier also appears in the context of qualified names. Name like some_class::some_member
(or some_namespace::some_name
) are called qualified names and the some_class::
part is a qualifier.
The idea that if something is an lvalue then you can modify it is totally incorrect. There are modifiable lvalues and non-modifiable lvalues. An object declared as const int i = 5
is an lvalue, yet you can't modify it. Ordinary functions are also lvalues in C++, yet you can't modify a function.
Related Topics
How to Initialize 'Std::Function' with a Member-Function
Why Isn't Memcpy Guaranteed to Be Safe for Non-Pod Types
Why Do I Need to Repeat Template Arguments of My Base Class in Member Initalizer List
How to Print Stack Trace for Caught Exceptions in C++ & Code Injection in C++
Can You Access Private Member Variables Across Class Instances
Better Variable Exploring When Debugging C++ Code with Eclipse/Cdt
How to Use Shared Library Created in C++ in a C Program
What Is This Crazy C++11 Syntax ==> Struct:Bar {} Foo {};
C++11 Std::Async Doesn't Work in Mingw
Const to Non-Const Conversion in C++
Is Using an Union in Place of a Cast Well Defined
How to Use a Boost Condition Variable to Wait for a Thread to Complete Processing