A cv-decomposition of a type T
is a sequence of
and
such that T is
“ ⋯ U” for ,
where
each is a set of cv-qualifiers ([basic.type.qualifier]), and
each is
“pointer to” ([dcl.ptr]),
“pointer to member of class of type” ([dcl.mptr]),
“array of ”, or
“array of unknown bound of” ([dcl.array]).

If designates an array,
the cv-qualifiers on the element type are also taken as
the cv-qualifiers of the array.

[Example 1: *end example*]

The type denoted by the type-id const int **
has three cv-decompositions,
taking U
as “int”,
as “pointer to const int”, and
as “pointer to pointer to const int”.

—
The n-tuple of cv-qualifiers after the first one
in the longest cv-decomposition of T, that is,
, is called the
cv-qualification signature of T.

The cv-combined type of two types T1 and T2
is the type T3
similar to T1 whose cv-decomposition is such that:

- for every , is the union of and ,
- if either or is “array of unknown bound of”, is “array of unknown bound of”, otherwise it is , and
- if the resulting is different from or , or the resulting is different from or , then const is added to every for ,

[Note 1: *end note*]

If a program could assign a pointer of type T** to a pointer of
type const T** (that is, if line #1 below were
allowed), a program could inadvertently modify a const object
(as it is done on line #2).

For example,
int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; // #1: not allowed
*pcc = &c;
*pc = 'C'; // #2: modifies a const object
}

— [Note 3: *end note*]

A prvalue of type “pointer to cv1 T” can be
converted to a prvalue of type “pointer to cv2 T” if
“cv2 T” is more cv-qualified than “cv1
T”.

A prvalue of type “pointer to member of X of type cv1
T” can be converted to a prvalue of type “pointer to member
of X of type cv2 T” if “cv2
T” is more cv-qualified than “cv1 T”.

—