Appendix B: coming from other languages
This appendix maps what you already know from C, Rust, Lisp, and Prolog onto the C++ you have now read. It is one page per language, and it uses the vocabulary of the chapter each idea belongs to.
From C
| You know | In C++ this is |
|---|---|
char* strings with a NUL terminator | std::string when owned, std::string_view when borrowed (ch10) |
| Arrays that decay to pointers | std::array, std::span, std::vector (ch11) |
FILE* and manual fclose | an RAII wrapper whose destructor releases the handle (ch05, ch28) |
errno and sentinel returns | std::expected and exceptions (ch09, ch28) |
printf with unchecked format strings | std::format and std::println, checked at compile time (ch10) |
qsort with void* and a function pointer | std::ranges::sort with a comparator and projection (ch12) |
Manual malloc/free | std::unique_ptr, std::vector, and the Rule of Zero (ch05, ch06) |
C code works in C++ through the boundary discipline of chapter 28: extern "C" for linkage, spans and string views for C data, and RAII wrappers for C resources.
C++ retains C calling conventions, adds ownership, and replaces manual resource handling and unchecked formatting with RAII and compile‑time checked formatting.
From Rust
| You know | In C++ this is |
|---|---|
| Value semantics | value semantics, move semantics, and copy elision (ch05, ch29) |
| Ownership | a name owns a value. Ownership transfers on move (ch05) |
| The borrow checker | the lifetime-safety profile, std::span, std::string_view, and -Wlifetime-safety (ch07) |
Option<T> | std::optional (ch03) |
Result<T, E> | std::expected (ch03, ch09) |
| Enums with data | std::variant plus std::visit (ch03) |
| Traits | concepts and requires clauses (ch17) |
Rust enforces ownership and lifetimes at compile time. C++ provides the same tools but relies on the lifetime‑safety analysis and disciplined APIs (see Chapter 7).
Both languages share the same mental model of ownership. The difference is where a violation is caught.
From Lisp
| You know | In C++ this is |
|---|---|
| Macros that expand source | templates, which rewrite type patterns and are instantiated at compile time (ch16) |
| Compile-time evaluation | constexpr, consteval, and the compile-time execution model (ch18) |
| A domain-specific language evaluated at compile time | the constexpr SQL capstone (ch22) |
| Functions as data | lambdas, std::function, and type erasure (ch14) |
| Recursive macros / term rewriting | template metaprogramming and pack expansion (ch16, ch21) |
C++ templates and constexpr supply compile‑time code generation analogous to Lisp macros.
Lisp rewrites source text. C++ rewrites type patterns and evaluates a restricted subset of the language at compile time.
From Prolog
| You know | In C++ this is |
|---|---|
| Unification | template argument deduction, which binds type parameters to concrete types (ch16) |
| Goal ordering / most specific rule | overload resolution and concept subsumption (ch17) |
| A term with a tag and arguments | std::variant plus std::visit (ch03) |
| Backtracking search | Not in the language. Express it explicitly with recursion or a search loop |
The strongest analogy is deduction: Prolog unifies a query against rules, and C++ unifies a call against template patterns and selects the most specific viable match. Chapter 17 frames concept subsumption in exactly these terms.
The difference is control. Prolog searches for a solution and can backtrack. C++ resolves a call once at compile time and does not search at runtime. The shared idea is pattern matching against a set of rules, with the most specific rule winning.