C++ Standards — what was added and why
The language changed dramatically with C++11: things that used to require template magic or third-party libraries moved into the standard. A new standard ships every three years; knowing what landed where is partly about portability and partly about picking the right tool for the job.
Topic map
- C++11 — move semantics,
auto, lambdas, smart pointers,nullptr,constexpr, threads. - C++14 — generic lambdas, return-type deduction, relaxed
constexpr,std::make_unique. - C++17 — structured bindings,
if constexpr,std::optional,std::string_view, fold expressions, parallel STL. - C++20 — concepts, coroutines, modules, ranges,
<=>,std::span,std::format. - C++23 —
std::expected,std::print,std::mdspan, deducingthis,std::generator. - C++26 (in flight) — reflection, contracts, senders/receivers,
std::execution.
C++11 — the revolution
The single largest shift in the language's history. What landed:
- Move semantics: rvalue references
T&&,std::move. Transfer ownership without copying. The basis forstd::unique_ptrand efficient containers. auto: compiler type deduction. Saved us fromstd::vector<std::map<std::string, int>>::const_iterator.- Lambdas:
[](int x) { return x * 2; }. Local functions with captured context. - Smart pointers:
std::unique_ptr,std::shared_ptr,std::weak_ptr. RAII for dynamic memory. nullptr: type-safe replacement for theNULLmacro.constexpr: compile-time evaluation (C++11 limited it to a singlereturn).- Threading:
std::thread,std::mutex,std::atomic. The first standard concurrency model. - Range-based for:
for (auto x : container). - Variadic templates:
template<typename... Ts>.
C++14 — polish
A "bug-fix release" that filled in C++11's gaps:
- Generic lambdas:
[](auto x) { ... }. - Return-type deduction for regular functions:
auto foo() { return 42; }. - Relaxed
constexpr:if,for, local variables are allowed. std::make_unique— forgotten in C++11.- Binary literals:
0b1010.
C++17 — practical wins
- Structured bindings:
auto [k, v] = *map.begin();. if constexpr: template branching without SFINAE.std::optional,std::variant,std::any— previously third-party vocabulary types.std::string_view— non-owning view on a string. Cheap to pass without a copy.- Fold expressions:
(args + ...)— variadic arguments collapsed into one expression. - Parallel STL:
std::execution::parforstd::sortand other algorithms. std::filesystem— a standardized path API.
⚠️ std::string_view does not own its data — outliving the source string is UB.
C++20 — the second mega-release
Comparable in scope to C++11:
- Concepts: type-safe template constraints replacing SFINAE.
template<std::integral T>
T square(T x) { return x * x; }
- Coroutines:
co_await,co_yield,co_return. Language support for stackless coroutines. - Modules:
import std;instead of#include. Solves header problems (macros, repeated parsing). - Ranges:
views::filter,views::transform, lazy composition replacing iterator pairs. <=>(spaceship): auto-generated comparison operators.std::span— non-owning view on an array (likestring_view, but for any element type).std::format— type-safe formatting (finally).constinit,consteval, expandedconstexpr(now nearly everywhere).
⚠️ Compiler and build-system support for C++20 is still incomplete — especially modules. Most production code in 2026 is still on C++17.
C++23 — the next step
std::expected<T, E>— value-or-error without exceptions, like Rust'sResult.std::print— finallyprint("Hello {}", name);.std::mdspan— multidimensional non-owning view (for scientific and ML code).- Deducing
this:template<typename Self> auto foo(this Self&& self). Unifies const/non-const overloads. std::generator— coroutine-based generator that consumesco_yield.
C++26 — incoming
Targeted as of 2026:
- Reflection — static reflection of types and members at compile time.
- Contracts —
pre/post/assertclauses in the signature. - Senders/Receivers (
std::execution) — structured async, replacing ad-hocstd::async. - Pattern matching —
inspectexpressions.
Common traps
| Mistake | Consequence |
|---|---|
| Assuming C++20 is production-ready everywhere | Modules and coroutines still have rough edges in gcc/clang/msvc |
Storing std::string_view past the source string's lifetime | UB — dangling view |
Putting large T inside std::optional<T> without thought | Stack bloat; for large objects use a pointer |
Using a feature without a __cpp_* feature-test guard | Build fails on the older compiler |
Confusing C++11 constexpr with C++14+ constexpr | C++11 forbids local variables and branches |
auto_ptr (C++03) in new code | Removed in C++17, replaced by unique_ptr |
| Relying on a TS or proposal before final vote | The feature may change or fail to land |
Interview relevance
Knowing the standards is a freshness signal. A junior should know the core C++11 features (move, smart pointers, lambdas). A middle should be at ease with C++17 (structured bindings, optional, string_view). A senior should discuss C++20/23 (concepts, coroutines, expected) and understand their support status.
Typical wrong answer: "std::optional shipped in C++20 along with concepts" — no, it shipped in C++17.
Popular question directions:
- Which features did C++11 add that matter most?
- What did C++17 ship, and why do we need
std::string_view? - What did C++20 add, and how production-ready is it?
- How does
std::expected(C++23) compare to exceptions? - Why do we need feature-test macros?