Search Knowledge

© 2026 LIBREUNI PROJECT

Modern C++ Programming / Foundations

Type System and Declarations

Fundamental Types and Type Categories

C++ provides a rich type system that balances low-level control with high-level abstractions. Every type belongs to one of several categories, each with distinct properties regarding copying, lifetime, and memory representation.

Built-in Fundamental Types

CategoryTypesGuaranteed Properties
Booleanbooltrue or false, implementation-defined size
Characterchar, wchar_t, char8_t, char16_t, char32_tCharacter encoding representation
Integershort, int, long, long longMinimum sizes specified
Floating-Pointfloat, double, long doubleIEEE 754 typical but not mandated
VoidvoidIncomplete type, used for “no value”

C++ guarantees size relationships: sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long). However, exact sizes are implementation-defined. Use <cstdint> for fixed-width types: int32_t, uint64_t, etc.

Type Deduction with auto

C++11 introduced auto for automatic type deduction, reducing verbosity while maintaining static typing. The compiler deduces types from initializers at compile time—there’s no runtime overhead.

auto x = 42;              // int
auto y = 3.14;            // double
auto z = "hello";         // const char*
auto ptr = new int{5};    // int*

// Complex types become manageable
auto it = vec.begin();    // std::vector<T>::iterator
auto lambda = [](int x) { return x * 2; };  // Closure type

Type Deduction Rules

The deduction follows template argument deduction rules with some exceptions:

  • Reference collapse: auto& preserves lvalue references
  • const stripping: auto removes top-level const (use const auto)
  • Array decay: Arrays decay to pointers unless auto&
Interactive Lab

Auto Type Deduction

int arr[5] = {1,2,3,4,5};
 p = arr;  // Deduces to int*
auto& r = arr;  // Deduces to int(&)[5]

decltype: Inspecting Expression Types

While auto deduces from initializers, decltype queries the type of any expression without evaluating it.

int x = 10;
decltype(x) y = 20;        // y is int

int& getRef();
decltype(getRef()) z = x;  // z is int&

// Combining auto and decltype (C++14 return type deduction)
auto func(int x) -> decltype(x * 2) {
    return x * 2;  // Return type is int
}

C++14 added decltype(auto) for perfect forwarding of return types:

template<typename Container>
decltype(auto) getElement(Container& c, size_t i) {
    return c[i];  // Preserves reference if container returns reference
}

Const Correctness

The const qualifier is fundamental to C++‘s type system, enabling the compiler to enforce immutability guarantees and enable optimizations.

Const Variables

const int max_retries = 3;  // Cannot be modified
// max_retries = 5;  // Compile error

int const alt_syntax = 5;  // Equivalent to const int

Const Pointers vs Pointer-to-Const

The placement of const determines what is immutable:

int value = 10;

const int* ptr1 = &value;  // Pointer to const int (can't modify *ptr1)
int* const ptr2 = &value;  // Const pointer to int (can't modify ptr2)
const int* const ptr3 = &value;  // Both const

*ptr1 = 20;  // Error: can't modify through ptr1
ptr1 = nullptr;  // OK: pointer itself is mutable

*ptr2 = 20;  // OK: can modify through ptr2
ptr2 = nullptr;  // Error: pointer itself is const

Mnemonic: Read right-to-left. const int* is “pointer to const int.”

Const Member Functions

Member functions can be marked const, promising not to modify object state:

class Point {
    int x_, y_;
public:
    int getX() const { return x_; }  // Doesn't modify object
    void setX(int x) { x_ = x; }     // Modifies object
};

const Point p{10, 20};
p.getX();  // OK
// p.setX(5);  // Error: can't call non-const method on const object

Type Aliases and Type Identity

C++11 introduced using for type aliases, superseding typedef:

// Old style (C++98)
typedef std::vector<int> IntVector;
typedef void (*FunctionPtr)(int);

// Modern style (C++11+)
using IntVector = std::vector<int>;
using FunctionPtr = void(*)(int);

// Template aliases (only possible with using)
template<typename T>
using Vec = std::vector<T>;

Vec<int> v;  // Equivalent to std::vector<int>

Signed vs Unsigned: A Design Choice

Integer types can be signed or unsigned. Mixing them in expressions causes implicit conversions that can be surprising:

int signed_val = -1;
unsigned int unsigned_val = 1;

if (signed_val < unsigned_val) {
    // This branch is NOT taken!
    // -1 converts to a large unsigned value
}

Best Practice: Prefer signed types for arithmetic, use unsigned only for bit manipulation or when the domain is truly non-negative (e.g., array indices—though even this is debated).

Conceptual Check

What is the type of `x` in: `const auto& x = 42;`?

Runtime Environment

Interactive Lab

1#include <iostream>
2#include <vector>
3 
4int main() {
5 const auto size = 10;
6 std::vector<int> vec(size, 42);
7
8 // auto deduces iterator type
9 auto it = vec.cbegin();
10
11 // decltype preserves exact type
12 decltype(vec[0]) first = vec[0]; // int&
13
14 std::cout << "Type deduction: " << *it << ", " << first << '\n';
15 return 0;
16}
System Console

Waiting for signal...