Namespaces
Variants
Actions

Type

From cppreference.com
< cpp‎ | language
 
 
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications(until C++17*)
noexcept specifier(C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr(C++11)
consteval(C++20)
constinit(C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr(C++11)
User-defined(C++11)
Utilities
Attributes(C++11)
Types
typedef declaration
Type alias declaration(C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
 
 

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

[edit]Type classification

The C++ type system consists of the following types:

(since C++11)
  • the type bool;
  • character types:
  • narrow character types:
  • ordinary character types: char, signedchar, unsignedchar[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: signedchar, short, int, long, longlong;
  • extended signed integer types (implementation-defined);
(since C++11)
  • unsigned integer types:
  • standard unsigned integer types: unsignedchar, unsignedshort, unsigned, unsignedlong, unsignedlonglong;
  • extended unsigned integer types (each corresponds to an extended signed integer type, and vice versa);
(since C++11)
(since C++23)
  • lvalue reference to object types;
  • lvalue reference to function types;
  • rvalue reference to object types;
  • rvalue reference to function types;
(since C++11)
(since C++11)
  1. signedchar and unsignedchar 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 constvolatile).

[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):

(since C++11)
  • cv-qualified versions of these types

The following types are collectively called implicit-lifetime types:

The following types are collectively called trivially copyable types:

The following types are collectively called standard-layout types:

(since C++11)

Type traits hierarchy diagram

cpp types v3.svg

Note: Elements of SVG image are clickable, but you must open the diagram in a new browser tab first

[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):

(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:

(since C++11)

[edit]Type naming

A name can be declared to refer to a type by means of:

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 intstatic_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 voidstd::function<void(int)> x = f;// type template parameter is a type-id "void(int)"std::function<auto(int)->void> y = f;// same   std::vector<int> v;// declaration of a vector of int sizeof(std::vector<int>);// type-id is "std::vector<int>"   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 expressionusing t =struct{int x;};// creates a new type and declares t as an alias of that type   sizeof(staticint);// error: storage class specifiers not part of type-specifier-seqstd::function<inlinevoid(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:

(until C++17)

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.

// givenstruct B {virtual ~B(){}};// polymorphic typestruct 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:

All other types are complete.

Any of the following contexts requires type T to be complete:

(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 yetextern 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:

externint arr[];// the type of arr is incompletetypedefint 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 328C++98 class members of incomplete type were not prohibited
if an object of the class type was never created
non-static class data members
need to be complete
CWG 977C++98 the point when an enumeration type becomes
complete in its definition was unclear
the type is complete once the
underlying type is determined
CWG 1362C++98 user-defined conversions to type T* or T& required T to be complete not required
CWG 2006C++98 cv-qualified void types were object type and complete type excluded from both categories
CWG 2448C++98 only cv-unqualified types could be integral and floating-point types allows cv-qualified types
CWG 2630C++98 it was unclear whether a class is considered complete outside
the translation unit where the definition of the class appears
the class is complete
if its definition is
reachable in this case
CWG 2643C++98 the type of a pointer to array of unknown bound
could not be completed (but it is already complete)
the pointed-to array type
cannot be completed
LWG 2139C++98 the meaning of “user-defined type” was unclear defines and uses “program-
defined type” instead
LWG 3119C++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]

[edit]See also

Type traits A compile-time template-based interfaces to query the properties of types

[edit]External links

1. Howard Hinnant's C++0x type tree
close