C++ Core Types

void

void: type with an empty set of values. It is an incomplete type that cannot be completed (consequently, objects of type void are disallowed). There are no arrays of void, nor references to void. However, pointers to void and functions returning type void (procedures in other languages) are permitted.

std::nullptr_t

(Defined in header <cstddef>)

typedef decltype(nullptr) nullptr_t;

(since C++11)

std::nullptr_t is the type of the null pointer literal, nullptr. It is a distinct type that is not itself a pointer type or a pointer to member type. All Its prvalues are null pointer constants.

sizeof(std::nullptr_t) is equal to sizeof(void*).

C++ Built-in Integer Types

Standard integer types

int: basic integer type. The keyword int may be omitted if any of the modifiers listed below are used. If no length modifiers are present, it's guaranteed to have a width of at least 16 bits. However, on 32/64 bit systems it is almost exclusively guaranteed to have width of at least 32 bits (see below).

Modifiers

They modify the basic integer type. Can be mixed in any order. Only one of each group can be present in type name.

Signedness:

signed: target type will have signed representation (this is the default if omitted)

unsigned: target type will have unsigned representation

Size:

short: target type will be optimized for space and will have width of at least 16 bits.

long: target type will have width of at least 32 bits.

long long: (since C++11) target type will have width of at least 64 bits.

Note: as with all type specifiers, any order is permitted: unsigned long long int and long int unsigned long name the same type.

std::size_t is the unsigned integer type of the result of the sizeof operator as well as the sizeof... operator and the alignof operator(since C++11).

Extended integer types

The extended integer types are implementation-defined. Note that fixed width integer types are typically aliases of the standard integer types.

(See https://en.cppreference.com/w/cpp/types/integer.html)

Boolean Type

bool: integer type, capable of holding one of the two values: true or false. The value of sizeof(bool) is implementation defined and might differ from 1.

C++ Built-in Character Types

Character types are integer types used for a character representation.

Types added in C++11:

Type added in C++20:


Besides the minimal bit counts, the C++ Standard guarantees that

1 == sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long).

Note: this allows the extreme case in which bytes are sized 64 bits, all types (including char) are 64 bits wide, and sizeof returns 1 for every type.

C++ Built-in Floating Point Types

Standard floating-point types

The following three types and their cv-qualified versions are collectively called standard floating-point types.

  • float: single precision floating-point type. Usually IEEE-754 binary32 format.
  • double: double precision floating-point type. Usually IEEE-754 binary64 format.
  • long double: extended precision floating-point type. Does not necessarily map to types mandated by IEEE-754.

Extended floating-point types

The extended floating-point types are implementation-defined. They may include fixed width floating-point types.

Removing Constantness, Reference-ness, Pointer-ness from Types

Constantness, Reference-ness, Pointer-ness can be removed from a type through:

The stripped type is available as a member alias named value.

For each of these struct's there is a reverse one that adds a feature instead of removing it.

Removing Reference-ness with std::remove_reference

Obtains the non-reference type to which T refers. The transformed type is aliased as member type remove_reference::type.

If T is a reference type (either lvalue reference or rvalue reference), this is the type to which it refers. Otherwise, it is the same as T, unchanged.

Notice that this class merely obtains a type using another type as model, but it does not transform values or objects between those types.


An example:

#include <iostream>
#include <type_traits>

int main() {
  typedef int&& rval_int;
  typedef std::remove_reference<int>::type A;
  typedef std::remove_reference<int&>::type B;
  typedef std::remove_reference<int&&>::type C;
  typedef std::remove_reference<rval_int>::type D;

  std::cout << std::boolalpha;
  std::cout << "typedefs of int:" << std::endl;
  std::cout << "A: " << std::is_same<int,A>::value << std::endl;
  std::cout << "B: " << std::is_same<int,B>::value << std::endl;
  std::cout << "C: " << std::is_same<int,C>::value << std::endl;
  std::cout << "D: " << std::is_same<int,D>::value << std::endl;

  return 0;
}

Its output:

typedefs of int:
A: true
B: true
C: true
D: true

Decay Types and std::decay in <type_traits>

Struct decay:

template <class T>
struct decay;

is used to obtain the decay type of T, which is aliased as member type decay::type.

The decay type of T is the same type that results from the standard conversions that happen when an lvalue expression is used as an rvalue, with its cv-qualifier stripped. This resembles the implicit conversions happening when an argument is passed by value to a function.

Put more simply, if T is a reference type (say const int&), then member value is the type referred to by T with its const-ness removed (int in this case).

Cases:

  • If T is a function type, a function-to-pointer conversion is applied and the decay type is the same as: add_pointer<T>::type
  • If T is an array type, an array-to-pointer conversion is applied and the decay type is the same as: add_pointer<remove_extent<remove_reference<T>::type>::type>::type. (This very much resembles C decay)
  • Otherwise, a regular lvalue-to-rvalue conversion is applied and the decay type is the same as: remove_cv<remove_reference<T>::type>::type.

Notice that this class merely obtains a type using another type as model, but it does not transform values or objects between those types.

An example:

#include <type_traits>

typedef std::decay<int>::type A;           // int
typedef std::decay<int&>::type B;          // int
typedef std::decay<int&&>::type C;         // int
typedef std::decay<const int&>::type D;    // int
typedef std::decay<int[2]>::type E;        // int*
typedef std::decay<int(int)>::type F;      // int(*)(int)

typedef int X[3];

These typedef's could be tested with:

#include <iostream>

int main() {
  std::cout << std::boolalpha;
  std::cout << "typedefs of int:" << std::endl;
  std::cout << "A: " << std::is_same<int,A>::value << std::endl;
  std::cout << "B: " << std::is_same<int,B>::value << std::endl;
  std::cout << "C: " << std::is_same<int,C>::value << std::endl;
  std::cout << "D: " << std::is_same<int,D>::value << std::endl;
  std::cout << "E: " << std::is_same<int,E>::value << std::endl;
  std::cout << "F: " << std::is_same<int,F>::value << std::endl;

  return 0;
}

Output:

typedefs of int:
A: true
B: true
C: true
D: true
E: false
F: false