< cpp‎ | language
Revision as of 19:33, 10 June 2014 by Cubbi (Talk | contribs)

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.


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)
  • The type std::nullptr_t (see also std::is_null_pointer)
  • Arithmetic types (see also std::is_arithmetic)
  • Floating-point types (float, double, long double) (see also std::is_floating_point)
  • Integral types (see also std::is_integral)
  • The type bool
  • Character types
  • Narrow character types (char, signed char, unsigned char)
  • Wide character types (char16_t, char32_t, wchar_t)
  • Signed integer types (short, int, long, long long)
  • Unsigned integer types (unsigned short, unsigned int, unsigned long, unsigned long long)
  • Compound types (see also std::is_compound)
  • Reference (see also std::is_reference)
  • Pointer (see also std::is_pointer)
  • Pointer to member (see also std::is_member_pointer)
  • Non-union class types (see also std::is_class)
  • Unions (see also std::is_union)

For every type other than reference and function, the type system supports three additional cv-qualified versions of that type (const, volatile, and const volatile)

Types are grouped in various categories based on their properties:

  • object type: any type other than void, function, or reference (that is, a type that an object may have). (see also std::is_object)
  • scalar type: arithmetic, pointer, enumeration, std::nullptr_t (see also std::is_scalar)
  • std::is_trivial, std::is_pod, std::is_literal_type, and other categories listed in the the type traits library or as named type requirements.

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 not be declared.

int* p;               // declration 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]"
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 that takes int and returns void
std::function<void(int)> x = f; // type template parameter is a type-id "void(int)"
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 declare new types
sizeof(static int); // error: storage class specifiers not part of type-specifier-seq
std::function<inline void(int)> f; // error: function specifiers aren't either

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:

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

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.

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.

Incomplete type

The following types are incomplete types

  • the type void
  • class type that has been declared (e.g. by forward declaration) but not defined
  • array of unknown size
  • array of elements of incomplete type
  • enumeration type from the point of declaration until the closing } of its enum-specifier