[*Note 1*: *end note*]

[basic.types] and the subclauses thereof
impose requirements on implementations regarding the representation
of types.

There are two kinds of types: fundamental types and compound types.

— For any object (other than a potentially-overlapping subobject) of trivially copyable type
T, whether or not the object holds a valid value of type
T, the underlying bytes ([intro.memory]) making up the
object can be copied into an array of
char,
unsigned char, or
std::byte ([cstddef.syn]).30

If the content of that array
is copied back into the object, the object shall
subsequently hold its original value.

[*Example 1*: constexpr std::size_t N = sizeof(T);
char buf[N];
T obj; // obj initialized to its original value
std::memcpy(buf, &obj, N); // between these two calls to std::memcpy, obj might be modified
std::memcpy(&obj, buf, N); // at this point, each subobject of obj of scalar type holds its original value
— *end example*]

For two distinct objects obj1 and obj2
of trivially copyable type T,
where neither obj1 nor obj2 is a potentially-overlapping subobject,
if the underlying bytes ([intro.memory]) making up
obj1 are copied into obj2,31
obj2 shall subsequently hold the same value as
obj1.

[*Example 2*: T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p contains
// the same value as the corresponding subobject in *t2p
— *end example*]

The *object representation*
of an object of type T is the
sequence of *N* unsigned char objects taken up
by the object of type T, where *N* equals
sizeof(T).

The *value representation*
of an object of type T is the set of bits
that participate in representing a value of type T.

A class that has been declared but not defined, an enumeration type in certain
contexts ([dcl.enum]), or an array of unknown
bound or of incomplete element type, is an
*incompletely-defined object type*.33

A class type (such as “class X”) can be incomplete at one
point in a translation unit and complete later on; the type
“class X” is the same type at both points.

The declared type
of an array object can be an array of incomplete class type and
therefore incomplete; if the class type is completed later on in the
translation unit, the array type becomes complete; the array type at
those two points is the same type.

The declared type of an array object
can be an array of unknown bound and therefore be incomplete at one
point in a translation unit and complete later on; the array types at
those two points (“array of unknown bound of T” and “array of
N T”) are different types.

The type of a pointer to array of
unknown bound, or of a type defined by a typedef declaration to
be an array of unknown bound, cannot be completed.

[*Example 3*: class X; // X is an incomplete type
extern X* xp; // xp is a pointer to an incomplete type
extern int arr[]; // the type of arr is incomplete
typedef int UNKA[]; // UNKA is an incomplete type
UNKA* arrp; // arrp is a pointer to an incomplete type
UNKA** arrpp;
void foo() {
xp++; // error: X is incomplete
arrp++; // error: incomplete type
arrpp++; // OK, sizeof UNKA* is known
}
struct X { int i; }; // now X is a complete type
int arr[10]; // now the type of arr is complete
X x;
void bar() {
xp = &x; // OK; type is “pointer to X''
arrp = &arr; // OK; qualification conversion ([conv.qual])
xp++; // OK, X is complete
arrp++; // error: UNKA can't be completed
}
— *end example*]

An *object type* is a (possibly cv-qualified) type that is not
a function type, not a reference type, and not cv void.

Arithmetic types ([basic.fundamental]), enumeration types,
pointer types, pointer-to-member types ([basic.compound]),
std::nullptr_t,
and
cv-qualified versions of these
types are collectively called
*scalar types*.

Scalar types, trivially copyable class types ([class.prop]),
arrays of such types, and cv-qualified versions of these
types are collectively called *trivially copyable types*.

Scalar types, trivial class types ([class.prop]),
arrays of such types and cv-qualified versions of these
types are collectively called
*trivial types*.

Scalar types, standard-layout class
types ([class.prop]), arrays of such types and
cv-qualified versions of these types
are collectively called *standard-layout types*.

Scalar types, implicit-lifetime class types ([class.prop]),
array types, and cv-qualified versions of these types
are collectively called *implicit-lifetime types*.

A type is a *literal type* if it is:

- cv void; or
- a scalar type; or
- a reference type; or
- an array of literal type; or
- a possibly cv-qualified class type that
has all of the following properties:
- it has a constexpr destructor ([dcl.constexpr]),
- it is either a closure type ([expr.prim.lambda.closure]), an aggregate type ([dcl.init.aggr]), or has at least one constexpr constructor or constructor template (possibly inherited ([namespace.udecl]) from a base class) that is not a copy or move constructor,
- if it is a union, at least one of its non-static data members is of non-volatile literal type, and
- if it is not a union, all of its non-static data members and base classes are of non-volatile literal types.

Two types *cv1* T1 and *cv2* T2 are
*layout-compatible types*
if T1 and T2 are the same type,
layout-compatible enumerations, or
layout-compatible standard-layout class types.

There are five *standard signed integer types*:
“signed char”, “short int”, “int”,
“long int”, and “long long int”.

In
this list, each type provides at least as much storage as those
preceding it in the list.

The standard and extended signed integer types are collectively called
*signed integer types*.

The range of representable values for a signed integer type is
to (inclusive),
where *N* is called the *width* of the type.

For each of the standard signed integer types,
there exists a corresponding (but different)
*standard unsigned integer type*:
“unsigned char”, “unsigned short int”,
“unsigned int”, “unsigned long int”, and
“unsigned long long int”.

Likewise, for each of the extended signed integer types,
there exists a corresponding *extended unsigned integer type*.

The standard and extended unsigned integer types
are collectively called *unsigned integer types*.

An unsigned integer type has the same width *N*
as the corresponding signed integer type.

The range of representable values for the unsigned type is
0 to (inclusive);
arithmetic for the unsigned type is performed modulo .

[*Note 2*: *end note*]

Unsigned arithmetic does not overflow.

Overflow for signed arithmetic yields undefined behavior ([expr.pre]).

— An unsigned integer type has the same
object representation,
value representation, and
alignment requirements ([basic.align])
as the corresponding signed integer type.

The value representation of a signed or unsigned integer type
comprises N bits, where N is the respective width.

Each set of values for any padding bits ([basic.types.general])
in the object representation are
alternative representations of the value specified by the value representation.

Except as specified above,
the width of a signed or unsigned integer type is
implementation-defined.

Each value x of an unsigned integer type with width N has
a unique representation ,
where each coefficient is either 0 or 1;
this is called the *base-2 representation* of x.

The base-2 representation of a value of signed integer type is
the base-2 representation of the congruent value
of the corresponding unsigned integer type.

The standard signed integer types and standard unsigned integer types
are collectively called the *standard integer types*, and the extended
signed integer types and extended
unsigned integer types are collectively called the
*extended integer types*.

A fundamental type specified to have
a signed or unsigned integer type as its *underlying type* has
the same object representation,
value representation,
alignment requirements ([basic.align]), and
range of representable values as the underlying type.

Further, each value has the same representation in both types.

Type char is a distinct type
that has an implementation-defined choice of
“signed char” or “unsigned char” as its underlying type.

The three types char, signed char, and unsigned char
are collectively called
*ordinary character types*.

For narrow character types,
each possible bit pattern of the object representation represents
a distinct value.

[*Note 6*: *end note*]

A bit-field of narrow character type whose width is larger than
the width of that type has padding bits; see [basic.types.general].

— Type wchar_t is a distinct type that has
an implementation-defined
signed or unsigned integer type as its underlying type.

Type bool is a distinct type that has
the same object representation,
value representation, and
alignment requirements as
an implementation-defined unsigned integer type.

The types char, wchar_t,
char8_t, char16_t, and char32_t
are collectively called *character types*.

The character types, bool,
the signed and unsigned integer types,
and cv-qualified versions ([basic.type.qualifier]) thereof,
are collectively termed
*integral types*.

A synonym for integral type is *integer type*.

[*Note 8*: *end note*]

Enumerations ([dcl.enum]) are not integral;
however, unscoped enumerations can be promoted to integral types
as specified in [conv.prom].

— The type double provides at least as much
precision as float, and the type long double provides at
least as much precision as double.

The set of values of the type
float is a subset of the set of values of the type
double; the set of values of the type double is a subset
of the set of values of the type long double.

The types
float, double, and long double,
and cv-qualified versions ([basic.type.qualifier]) thereof,
are collectively termed
*standard floating-point types*.

An implementation may also provide additional types
that represent floating-point values and define them (and cv-qualified versions thereof) to be
*extended floating-point types*.

The standard and extended floating-point types
are collectively termed *floating-point types*.

[*Note 9*: *end note*]

Any additional implementation-specific types representing floating-point values
that are not defined by the implementation to be extended floating-point types
are not considered to be floating-point types, and
this document imposes no requirements on them or
their interactions with floating-point types.

—
Except as specified in [basic.extended.fp],
the object and value representations and accuracy of operations
of floating-point types are implementation-defined.

A type cv void
is an incomplete type that cannot be completed; such a type has
an empty set of values.

It is used as the return
type for functions that do not return a value.

Any expression can be
explicitly converted to type
cv void ([expr.type.conv], [expr.static.cast], [expr.cast]).

An expression of type cv void shall
be used only as an expression statement ([stmt.expr]), as an operand
of a comma expression ([expr.comma]), as a second or third operand
of ?: ([expr.cond]), as the operand of
typeid, noexcept, or decltype, as
the expression in a return statement ([stmt.return]) for a function
with the return type cv void, or as the operand of an explicit conversion
to type cv void.

Such values participate in the pointer and the
pointer-to-member conversions ([conv.ptr], [conv.mem]).

If the implementation supports an extended floating-point type ([basic.fundamental])
whose properties are specified by
the ISO/IEC/IEEE 60559 floating-point interchange format binary16,
then the *typedef-name* std::float16_t
is defined in the header <stdfloat> and names such a type,
the macro __STDCPP_FLOAT16_T__ is defined ([cpp.predefined]), and
the floating-point literal suffixes f16 and F16
are supported ([lex.fcon]).

If the implementation supports an extended floating-point type
whose properties are specified by
the ISO/IEC/IEEE 60559 floating-point interchange format binary32,
then the *typedef-name* std::float32_t
is defined in the header <stdfloat> and names such a type,
the macro __STDCPP_FLOAT32_T__ is defined, and
the floating-point literal suffixes f32 and F32 are supported.

If the implementation supports an extended floating-point type
whose properties are specified by
the ISO/IEC/IEEE 60559 floating-point interchange format binary64,
then the *typedef-name* std::float64_t
is defined in the header <stdfloat> and names such a type,
the macro __STDCPP_FLOAT64_T__ is defined, and
the floating-point literal suffixes f64 and F64 are supported.

If the implementation supports an extended floating-point type
whose properties are specified by
the ISO/IEC/IEEE 60559 floating-point interchange format binary128,
then the *typedef-name* std::float128_t
is defined in the header <stdfloat> and names such a type,
the macro __STDCPP_FLOAT128_T__ is defined, and
the floating-point literal suffixes f128 and F128 are supported.

If the implementation supports an extended floating-point type
with the properties, as specified by ISO/IEC/IEEE 60559, of
radix (b) of 2,
storage width in bits (k) of 16,
precision in bits (p) of 8,
maximum exponent (emax) of 127, and
exponent field width in bits (w) of 8, then
the *typedef-name* std::bfloat16_t
is defined in the header <stdfloat> and names such a type,
the macro __STDCPP_BFLOAT16_T__ is defined, and
the floating-point literal suffixes bf16 and BF16 are supported.

Table 16: Properties of named extended floating-point types [tab:basic.extended.fp]

Parameter | float16_t | float32_t | float64_t | float128_t | bfloat16_t | |

ISO/IEC/IEEE 60559 name | binary16 | binary32 | binary64 | binary128 | ||

k, storage width in bits | 16 | 32 | 64 | 128 | 16 | |

p, precision in bits | 11 | 24 | 53 | 113 | 8 | |

emax, maximum exponent | 15 | 127 | 1023 | 16383 | 127 | |

w, exponent field width in bits | 5 | 8 | 11 | 15 | 8 |

Compound types can be constructed in the following ways:

*arrays*of objects of a given type, [dcl.array];*classes*containing a sequence of objects of various types ([class]), a set of types, enumerations and functions for manipulating these objects ([class.mfct]), and a set of restrictions on the access to these entities ([class.access]);*unions*, which are classes capable of containing objects of different types at different times, [class.union];*enumerations*, which comprise a set of named constant values, [dcl.enum];*pointers to non-static class members*,35 which identify members of a given type within objects of a given class, [dcl.mptr].Pointers to data members and pointers to member functions are collectively called*pointer-to-member*types.

These methods of constructing types can be applied recursively;
restrictions are mentioned in [dcl.meaning].

Constructing a type such that the number of
bytes in its object representation exceeds the maximum value representable in
the type std::size_t ([support.types]) is ill-formed.

The type of a pointer that can designate a function
is called a *function pointer type*.

Except for pointers to static members, text referring to “pointers”
does not apply to pointers to members.

Pointers to incomplete types are
allowed although there are restrictions on what can be done with
them ([basic.align]).

Every value of pointer type is one of the following:

- a
*pointer to*an object or function (the pointer is said to*point*to the object or function), or - a
*pointer past the end of*an object ([expr.add]), or -
the
*null pointer value*for that type, or -
an
*invalid pointer value*.

A value of a
pointer type
that is a pointer to or past the end of an object
*represents the address* of
the first byte in memory ([intro.memory]) occupied by the object36
or the first byte in memory
after the end of the storage occupied by the object,
respectively.

[*Note 2*: *end note*]

A pointer past the end of an object ([expr.add])
is not considered to point to an unrelated object
of the object's type,
even if the unrelated object is located at that address.

A pointer value becomes invalid
when the storage it denotes
reaches the end of its storage duration;
see [basic.stc].

—
For purposes of pointer arithmetic ([expr.add])
and comparison ([expr.rel], [expr.eq]),
a pointer past the end of the last element of
an array x of n elements
is considered to be equivalent to
a pointer to a hypothetical array element n of x and
an object of type T that is not an array element
is considered to belong to an array with one element of type T.

The value representation of
pointer types is implementation-defined.

Pointers to
layout-compatible types shall
have the same value representation and alignment
requirements ([basic.align]).

[*Note 3*: *end note*]

Pointers to over-aligned types have no special
representation, but their range of valid values is restricted by the extended
alignment requirement.

— Two objects *a* and *b* are *pointer-interconvertible* if:

- they are the same object, or
- one is a union object and the other is a non-static data member of that object ([class.union]), or
- one is a standard-layout class object and the other is the first non-static data member of that object or any base class subobject of that object ([class.mem]), or
- there exists an object
*c*such that*a*and*c*are pointer-interconvertible, and*c*and*b*are pointer-interconvertible.

If two objects are pointer-interconvertible,
then they have the same address,
and it is possible to obtain a pointer to one
from a pointer to the other
via a reinterpret_cast ([expr.reinterpret.cast]).

A byte of storage *b*
is *reachable through*
a pointer value that points to an object *x*
if there is an object *y*,
pointer-interconvertible with *x*,
such that *b* is within the storage occupied by
*y*, or the immediately-enclosing array object
if *y* is an array element.

Each type other than a function or reference type
is part of a group of four distinct, but related, types:
a *cv-unqualified* version,
a *const-qualified* version,
a *volatile-qualified* version, and
a *const-volatile-qualified* version.

The types in each such group shall have
the same representation and alignment requirements ([basic.align]).37

A function or reference type is always cv-unqualified.

- A
*const volatile object*is an object of type const volatile T, a non-mutable subobject of a const volatile object, a const subobject of a volatile object, or a non-mutable volatile subobject of a const object.

[*Note 1*: *end note*]

The type of an object ([intro.object]) includes
the *cv-qualifier**s* specified in the
*decl-specifier-seq* ([dcl.spec]),
*declarator* ([dcl.decl]),
*type-id* ([dcl.name]), or
*new-type-id* ([expr.new])
when the object is created.

— Except for array types, a compound type ([basic.compound]) is not cv-qualified by the
cv-qualifiers (if any) of the types from which it is compounded.

An array type whose elements are cv-qualified
is also considered to have the same cv-qualifications
as its elements.

[*Note 2*: *end note*]

Cv-qualifiers applied to an array
type attach to the underlying element type, so the notation
“cv T”, where T is an array type, refers to
an array whose elements are so-qualified ([dcl.array]).

— [*Note 3*: — *end note*]

There is a partial ordering on cv-qualifiers, so that a type can be
said to be *more cv-qualified* than another.

, used in the description of types,
represents an arbitrary set of cv-qualifiers, i.e., one of
{const}, {volatile}, {const,
volatile}, or the empty set.

Every integer type has an *integer conversion rank* defined as follows:

- No two signed integer types other than char and signed char (if char is signed) have the same rank, even if they have the same representation.
- The rank of a signed integer type is greater than the rank of any signed integer type with a smaller width.
- The rank of long long int is greater than the rank of long int, which is greater than the rank of int, which is greater than the rank of short int, which is greater than the rank of signed char.
- The rank of any unsigned integer type equals the rank of the corresponding signed integer type.
- The rank of any standard integer type is greater than the rank of any extended integer type with the same width.
- The rank of bool is less than the rank of all standard integer types.
- The ranks of char8_t, char16_t, char32_t, and wchar_t equal the ranks of their underlying types ([basic.fundamental]).
- The rank of any extended signed integer type relative to another extended signed integer type with the same width is implementation-defined, but still subject to the other rules for determining the integer conversion rank.
- For all integer types T1, T2, and T3, if T1 has greater rank than T2 and T2 has greater rank than T3, then T1 has greater rank than T3.

[*Note 1*: *end note*]

The integer conversion rank is used in the definition of the integral
promotions ([conv.prom]) and the usual arithmetic
conversions ([expr.arith.conv]).

— Every floating-point type has a *floating-point conversion rank*
defined as follows:

- The rank of a floating point type T is greater than the rank of any floating-point type whose set of values is a proper subset of the set of values of T.
- The rank of long double is greater than the rank of double, which is greater than the rank of float.
- Two extended floating-point types with the same set of values have equal ranks.
- An extended floating-point type with the same set of values as exactly one cv-unqualified standard floating-point type has a rank equal to the rank of that standard floating-point type.
- An extended floating-point type with the same set of values as more than one cv-unqualified standard floating-point type has a rank equal to the rank of double.

Floating-point types that have equal floating-point conversion ranks
are ordered by floating-point conversion subrank.

The subrank forms a total order among types with equal ranks.

The types
std::float16_t,
std::float32_t,
std::float64_t, and
std::float128_t ([stdfloat.syn])
have a greater conversion subrank than any standard floating-point type
with equal conversion rank.

Otherwise, the conversion subrank order is
implementation-defined.

[*Note 3*: *end note*]

The floating-point conversion rank and subrank are used in
the definition of the usual arithmetic conversions ([expr.arith.conv]).

—