Modern C++

Modern C++ encompasses C++11 through C++20 and C++23. It emphasizes type safety, RAII, zero-cost abstractions, compile-time evaluation, and expressive standard library utilities.

  • C++23: std::print/println, std::expected (monadic error handling), std::string::contains, std::mdspan, multidimensional subscript operator[].
  • C++20: Concepts, Ranges, Coroutines, Modules, Three-way comparison (<=>), std::format, std::span.
  • C++17: Structured bindings, std::string_view, std::optional, std::variant, std::filesystem, if constexpr.
  • C++14: Generic lambdas, std::make_unique, return type deduction.
  • C++11: Smart pointers (unique_ptr, shared_ptr), move semantics & rvalue references, lambdas, auto, nullptr.

Modern Ownership & RAII

Resource Acquisition Is Initialization (RAII) ties resource management directly to object lifetime:

  • Resource acquisition occurs in the constructor.

  • Resource release occurs in the destructor.

  • Read more: Smart Pointers

Concepts & Constraints (C++20)

Concepts specify compile-time template requirements, eliminating cryptic template error traces:

#include <concepts>

template <typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;

template <Numeric T>
T add(T a, T b) {
  return a + b;
}

// Or using terse syntax:
auto multiply(Numeric auto a, Numeric auto b) {
  return a * b;
}

Ranges & Views (C++20 / C++23)

Ranges allow composable, lazy pipeline transformations over collections without manual iterator pairs:

#include <iostream>
#include <vector>
#include <ranges>

std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8};

auto even_squares = numbers
    | std::views::filter([](int n) { return n % 2 == 0; })
    | std::views::transform([](int n) { return n * n; });

for (int val : even_squares) {
  std::cout << val << " "; // 4 16 36 64
}

Modern Printing & Formatting (std::format / std::print)

std::format (C++20) and std::print (C++23) provide safe, extensible, high-performance replacements for printf and std::cout:

#include <format>
#include <print>

// C++20 formatting
std::string msg = std::format("User ID: {}, Balance: ${:.2f}", 101, 45.5);

// C++23 direct printing (faster than cout, eliminates printf formatting vulnerabilities)
std::println("Hello, {}! You have {} unread messages.", "Sam", 5);

Monadic Error Handling (std::expected, C++23)

Represents either an expected value of type T or an unexpected error of type E, offering an efficient alternative to exceptions:

#include <expected>
#include <string>

enum class ParseError { kInvalidChar, kOverflow };

std::expected<int, ParseError> parse_number(std::string_view str) {
  if (str.empty()) return std::unexpected(ParseError::kInvalidChar);
  // ...
  return 42;
}

std::span (C++20)

A non-owning view over any contiguous sequence of objects (C arrays, std::vector, std::array):

#include <span>
#include <vector>

void process_data(std::span<const int> data) {
  for (int item : data) {
    // ...
  }
}

std::vector<int> vec = {1, 2, 3};
int raw_arr[] = {4, 5, 6};
process_data(vec);      // Works seamlessly without copying
process_data(raw_arr);  // Works seamlessly

Modules (C++20)

Modules provide component boundaries that compile once, eliminating header file inclusion overhead and macro leakage:

// math.ixx / math.cppm
export module math;

export int square(int x) {
  return x * x;
}

// main.cpp
import math;
import <iostream>;

int main() {
  std::cout << square(5) << '\n';
}

Coroutines (C++20)

Functions that can suspend and resume execution via co_await, co_yield, or co_return. Commonly used for asynchronous I/O and lazy generator sequences.

Designated Initializers (C++20)

struct Config {
  std::string host = "localhost";
  int port = 8080;
  bool use_ssl = false;
};

Config cfg = {
  .port = 9000,
  .use_ssl = true,
};

Spaceship Operator (<=>, C++20)

Auto-generates all 6 relational comparison operators (==, !=, <, <=, >, >=):

#include <compare>

struct Version {
  int major;
  int minor;
  int patch;
  auto operator<=>(const Version&) const = default;
};