← C++, End to End

C++, End to End

A Tour of Modern C++ (11 Through 23)

C++ has changed more in the last fifteen years than in the twenty before that. This chapter is a survey: what each standard actually added, at a practical level. Several of these (auto, lambdas, smart pointers, move semantics) already got full chapters earlier in this course and are just listed here for context, not re-explained.

C++11: the big one

  • auto and range-based for: type deduction and simpler iteration (covered earlier)
  • Move semantics, rvalue references, smart pointers (covered earlier, this is arguably the single biggest change to how idiomatic C++ is written)
  • Lambdas (covered earlier)
  • nullptr replacing the old NULL macro (which was really just 0 in disguise, causing real overload-resolution bugs)
  • Scoped enums, override/final (covered earlier)
  • Uniform initialization with braces {}

C++14: a smaller, cleanup release

  • Generic lambdas: auto in a lambda's parameter list, letting one lambda work across multiple types
  • Relaxed constexpr rules: constexpr functions could now contain loops and multiple statements, not just a single return expression
c++ · live, editable, runnableOpen in Compiler Explorer ↗

C++17: quality of life

  • Structured bindings: unpack a pair/tuple/struct into named variables in one line
  • if with an initializer: if (auto it = m.find(key); it != m.end())
  • std::optional, std::variant, std::any: safer alternatives to nullable pointers and unsafe unions
  • Fold expressions for variadic templates (covered in the templates chapter)
c++ · live, editable, runnableOpen in Compiler Explorer ↗

C++20: a second C++11

  • Concepts (covered in the templates chapter): named, readable template constraints
  • Ranges: composable operations over sequences, e.g. std::views::filter and std::views::transform, without hand-writing loops or intermediate containers
  • The spaceship operator <=>: write one comparison and get all six relational operators generated for you
  • Coroutines: language support for suspendable functions (co_await, co_yield). Powerful, but the library-level ergonomics (writing your own coroutine types) are still genuinely fiddly; most people use coroutines through a library that wraps the hard parts rather than building the machinery by hand
  • Modules: an alternative to the #include/header-file model, meant to speed up compilation and avoid macro leakage. Compiler and build-system support is still catching up as of this writing, so don't be surprised if module support varies noticeably between toolchains
c++ · live, editable, runnableOpen in Compiler Explorer ↗

That ranges pipeline reads left to right (filter, then transform) instead of nesting function calls inside out, and importantly, it's lazy: nothing is actually computed until you iterate over the result.

C++23: still settling in

  • std::expected<T, E>: a return type that's either a value or an error, without throwing, a genuine standard-library alternative to exceptions for error handling
  • "Deducing this": lets a member function deduce its own object parameter, simplifying some patterns that previously needed duplicated const/non-const overloads
  • std::print / std::println: type-safe, format-string-based printing (from C++20's std::format, extended in C++23), meant to eventually be the default way you write to stdout instead of iostream chaining

Compiler and standard library support for C++23 features is genuinely uneven as of this writing. Treat the C++23 examples in this course as illustrative of the direction the language is heading, and double-check your specific toolchain's support before relying on them in real code.

Try it yourself: rewrite a loop as a ranges pipeline

Take a plain for loop that filters and transforms a vector into a new vector, and rewrite it using std::views::filter and std::views::transform, then compare readability.

c++ · live, editable, runnableOpen in Compiler Explorer ↗