Type - cppreference.com (original) (raw)
Objects, references, functions including function template specializations, and expressions have a property called type, which both restricts the operations that are permitted for those entities and provides semantic meaning to the otherwise generic sequences of bits.
Contents
- 1 Type classification
- 2 Other categories
- 3 Program-defined type
- 4 Type naming
- 5 Elaborated type specifier
- 6 Static type
- 7 Dynamic type
- 8 Incomplete type
- 9 Defect reports
- 10 References
- 11 See also
- 12 External links
[edit] Type classification
The C++ type system consists of the following types:
fundamental types (see also std::is_fundamental):
the type void (see also std::is_void);
arithmetic types (see also std::is_arithmetic):
integral types (including cv-qualified versions, see also std::is_integral, a synonym for integral type is integer type):
the type bool;
character types:
narrow character types:
ordinary character types: char, signed char, unsigned char[1]
the type char8_t | (since C++20) |
---|
wide character types: char16_t, char32_t, (since C++11)wchar_t;
signed integer types:
standard signed integer types: signed char, short, int, long, long long;
extended signed integer types (implementation-defined); | (since C++11) |
---|
unsigned integer types:
standard unsigned integer types: unsigned char, unsigned short, unsigned, unsigned long, unsigned long long;
extended unsigned integer types (each corresponds to an extended signed integer type, and vice versa); | (since C++11) |
---|
floating-point types (see also std::is_floating_point):
standard floating-point types: float, double, long double and their cv-qualified versions;
extended floating-point types (including cv-qualified versions): fixed width floating-point types; other implementation-defined extended floating-point types; | (since C++23) |
---|
compound types (see also std::is_compound):
reference types (see also std::is_reference):
lvalue reference types (see also std::is_lvalue_reference):
lvalue reference to object types;
lvalue reference to function types;
pointer types (see also std::is_pointer):
pointer-to-member types (see also std::is_member_pointer):
pointer-to-data-member types (see also std::is_member_object_pointer);
pointer-to-member-function types (see also std::is_member_function_pointer);
array types (see also std::is_array);
function types (see also std::is_function);
enumeration types (see also std::is_enum);
non-union types (see also std::is_class);
union types (see also std::is_union).
- ↑ signed char and unsigned char are narrow character types, but they are not character types. In other words, the set of narrow character types is not a subset of the set of character types.
For every non-cv-qualified type other than reference and function, the type system supports three additional cv-qualified versions of that type (const, volatile, and const volatile).
[edit] Other categories
An object type (see also std::is_object) is a (possibly cv-qualified) type that is not a function type, not a reference type, and not (possibly cv-qualified) void.
The following types are collectively called scalar types (see also std::is_scalar):
- arithmetic types
- enumeration types
- pointer types
- pointer-to-member types
- cv-qualified versions of these types
The following types are collectively called implicit-lifetime types:
- scalar types
- implicit-lifetime class types
- array types
- cv-qualified versions of these types
The following types are collectively called trivially copyable types: scalar types trivially copyable class types arrays of such types cv-qualified versions of these types The following types are collectively called standard-layout types: scalar types standard-layout class types arrays of such types cv-qualified versions of these types | (since C++11) |
---|
Type traits hierarchy diagram |
---|
[edit] Deprecated categories
The following types are collectively called POD types (see also std::is_pod): scalar types POD classes arrays of such types cv-qualified versions of these types | (deprecated in C++20) |
---|---|
The following types are collectively called trivial types (see also std::is_trivial): scalar types trivial class types arrays of such types cv-qualified versions of these types | (since C++11)(deprecated in C++26) |
[edit] Program-defined type
A program-defined specialization is an explicit specialization or partial specialization that is not part of the C++ standard library and not defined by the implementation.
A program-defined type is one of the following types:
- A non-closure(since C++11) class type or enumeration type that is not part of the C++ standard library and not defined by the implementation.
- An instantiation of a program-defined specialization.
[edit] Type naming
A name can be declared to refer to a type by means of:
- class declaration;
- union declaration;
- enum declaration;
- typedef declaration;
- type alias declaration.
Types that do not have names often need to be referred to in C++ programs; the syntax for that is known as type-id. The syntax of the type-id that names type T
is exactly the syntax of a declaration of a variable or function of type T
, with the identifier omitted, except that decl-specifier-seq of the declaration grammar is constrained to type-specifier-seq, and that new types may be defined only if the type-id appears on the right-hand side of a non-template type alias declaration.
int* p; // declaration of a pointer to int static_cast<int*>(p); // type-id is "int*" int a[3]; // declaration of an array of 3 int new int[3]; // type-id is "int[3]" (called new-type-id) int ((x[2])())[3]; // declaration of an array of 2 pointers to functions // returning pointer to array of 3 int new (int (([2])())[3]); // type-id is "int (([2])())[3]" void f(int); // declaration of a function taking int and returning void std::function<void(int)> x = f; // type template parameter is a type-id "void(int)" std::function<auto(int) -> void> y = f; // same std::vector v; // declaration of a vector of int sizeof(std::vector); // type-id is "std::vector" struct { int x; } b; // creates a new type and declares an object b of that type sizeof(struct { int x; }); // error: cannot define new types in a sizeof expression using t = struct { int x; }; // creates a new type and declares t as an alias of that type sizeof(static int); // error: storage class specifiers not part of type-specifier-seq std::function<inline void(int)> f; // error: neither are function specifiers
The declarator part of the declaration grammar with the name removed is referred to as abstract-declarator.
Type-id may be used in the following situations:
- to specify the target type in cast expressions;
- as arguments to sizeof, alignof, alignas, new, and typeid;
- on the right-hand side of a type alias declaration;
- as the trailing return type of a function declaration;
- as the default argument of a template type parameter;
- as the template argument for a template type parameter;
Type-id can be used with some modifications in the following situations:
- in the parameter list of a function (when the parameter name is omitted), type-id uses decl-specifier-seq instead of type-specifier-seq (in particular, some storage class specifiers are allowed);
- in the name of a user-defined conversion function, the abstract declarator cannot include function or array operators.
[edit] Elaborated type specifier
Elaborated type specifiers may be used to refer to a previously-declared class name (class, struct, or union) or to a previously-declared enum name even if the name was hidden by a non-type declaration. They may also be used to declare new class names.
See elaborated type specifier for details.
[edit] Static type
The type of an expression that results from the compile-time analysis of the program is known as the static type of the expression. The static type does not change while the program is executing.
[edit] Dynamic type
If some glvalue expression refers to a polymorphic object, the type of its most derived object is known as the dynamic type.
// given struct B { virtual ~B() {} }; // polymorphic type struct D : B {}; // polymorphic type D d; // most-derived object B* ptr = &d; // the static type of (*ptr) is B // the dynamic type of (*ptr) is D
For prvalue expressions, the dynamic type is always the same as the static type.
[edit] Incomplete type
The following types are incomplete types:
- the type void (possibly cv-qualified);
- incompletely-defined object types:
- class type that has been declared (e.g. by forward declaration) but not defined;
- array of unknown bound;
- array of elements of incomplete type;
- enumeration type from the point of declaration until its underlying type is determined.
All other types are complete.
Any of the following contexts requires type T
to be complete:
- definition of or call to a function with return type
T
or argument typeT
; - definition of an object of type
T
; - declaration of a non-static class data member of type
T
; - new expression for an object of type
T
or an array whose element type isT
; - lvalue-to-rvalue conversion applied to a glvalue of type
T
; - an implicit or explicit conversion to type
T
; - a standard conversion, dynamic_cast, or static_cast to type T* or T&, except when converting from the null pointer constant or from a pointer to possibly cv-qualified void;
- class member access operator applied to an expression of type
T
; - typeid, sizeof, or alignof operator applied to type
T
; - arithmetic operator applied to a pointer to
T
; - definition of a class with base class
T
; - assignment to an lvalue of type
T
; - a handler of type
T
, T&, or T*.
(In general, when the size and layout of T
must be known.)
If any of these situations occur in a translation unit, the definition of the type must appear in the same translation unit. Otherwise, it is not required.
An incompletely-defined object type can be completed:
- A class type (such as class X) might be regarded as incomplete at one point in a translation unit and regarded as complete later on; the type class X is the same type at both points:
struct X; // declaration of X, no definition provided yet extern X* xp; // xp is a pointer to an incomplete type: // the definition of X is not reachable void foo() { xp++; // ill-formed: X is incomplete } struct X { int i; }; // definition of X X x; // OK: the definition of X is reachable void bar() { xp = &x; // OK: type is “pointer to X” xp++; // OK: X is complete }
- The declared type of an array object might 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 might 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 NT
") are different types.
The type of a pointer or reference to array of unknown bound permanently points to or refers to an incomplete type. An array of unknown bound named by a typedef declaration permanently refers to an incomplete type. In either case, the array type cannot be completed:
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() { arrp++; // error: UNKA is an incomplete type arrpp++; // OK: sizeof UNKA* is known } int arr[10]; // now the type of arr is complete void bar() { arrp = &arr; // OK: qualification conversion (since C++20) arrp++; // error: UNKA cannot be completed }
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 328 | C++98 | class members of incomplete type were not prohibitedif an object of the class type was never created | non-static class data membersneed to be complete |
CWG 977 | C++98 | the point when an enumeration type becomescomplete in its definition was unclear | the type is complete once theunderlying type is determined |
CWG 1362 | C++98 | user-defined conversions to type T* or T& required T to be complete | not required |
CWG 2006 | C++98 | cv-qualified void types were object type and complete type | excluded from both categories |
CWG 2448 | C++98 | only cv-unqualified types could be integral and floating-point types | allows cv-qualified types |
CWG 2630 | C++98 | it was unclear whether a class is considered complete outsidethe translation unit where the definition of the class appears | the class is completeif its definition isreachable in this case |
CWG 2643 | C++98 | the type of a pointer to array of unknown boundcould not be completed (but it is already complete) | the pointed-to array typecannot be completed |
LWG 2139 | C++98 | the meaning of “user-defined type” was unclear | defines and uses “program-defined type” instead |
LWG 3119 | C++11 | it was unclear whether closure types are program-defined types | made clear |
[edit] References
C++23 standard (ISO/IEC 14882:2024):
6.8.2 Fundamental types [basic.fundamental]
C++20 standard (ISO/IEC 14882:2020):
6.8.2 Fundamental types [basic.fundamental]
C++17 standard (ISO/IEC 14882:2017):
6.9.1 Fundamental types [basic.fundamental]
C++14 standard (ISO/IEC 14882:2014):
3.9.1 Fundamental types [basic.fundamental]
C++11 standard (ISO/IEC 14882:2011):
3.9.1 Fundamental types [basic.fundamental]
C++98 standard (ISO/IEC 14882:1998):
3.9.1 Fundamental types [basic.fundamental]