C++20 New Features: Complete Guide and Reference
C++20 New Features: Complete Guide and Reference
C++20 was a major update introducing revolutionary features like concepts, ranges, coroutines, and modules. This guide covers all C++20 features.
Core Language Features
1. Concepts
Named requirements for templates.
#include <concepts>
// Simple concept
template<typename T>
concept Addable = requires(T a, T b) {
{ a + b } -> std::convertible_to<T>;
};
// Using concept
template<Addable T>
T add(T a, T b) {
return a + b;
}
// Standard concepts
template<std::integral T>
void process_integer(T value) {
// T must be integral type
}
template<std::floating_point T>
void process_float(T value) {
// T must be floating point
}
// Custom concept
template<typename T>
concept Printable = requires(T t) {
std::cout << t;
};
template<Printable T>
void print(T value) {
std::cout << value << std::endl;
}
// Concept with multiple requirements
template<typename T>
concept Sortable = std::totally_ordered<T> && requires(T a, T b) {
{ a < b } -> std::convertible_to<bool>;
};
// Abbreviated function templates
void func(std::integral auto x) {
// x is any integral type
}
auto add(std::addable auto a, std::addable auto b) {
return a + b;
}
2. Ranges
Modern iteration and algorithms.
#include <ranges>
#include <vector>
#include <algorithm>
std::vector<int> vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// Range-based algorithms
auto result = vec | std::views::filter([](int x) { return x % 2 == 0; })
| std::views::transform([](int x) { return x * 2; })
| std::views::take(3);
for (auto val : result) {
std::cout << val << " "; // 4 8 12
}
// Range views
auto evens = vec | std::views::filter([](int x) { return x % 2 == 0; });
auto squares = vec | std::views::transform([](int x) { return x * x; });
auto first_five = vec | std::views::take(5);
auto skip_first = vec | std::views::drop(2);
// Range algorithms
std::ranges::sort(vec);
auto it = std::ranges::find(vec, 5);
auto count = std::ranges::count_if(vec, [](int x) { return x > 5; });
// Iota view (generate sequence)
auto numbers = std::views::iota(1, 10); // 1, 2, ..., 9
// Reverse view
for (auto val : vec | std::views::reverse) {
std::cout << val << " ";
}
3. Coroutines
Suspension and resumption of functions.
#include <coroutine>
#include <iostream>
// Generator coroutine
template<typename T>
struct Generator {
struct promise_type {
T current_value;
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
std::suspend_always yield_value(T value) {
current_value = value;
return {};
}
Generator get_return_object() {
return Generator{std::coroutine_handle<promise_type>::from_promise(*this)};
}
void unhandled_exception() {}
};
std::coroutine_handle<promise_type> coro;
Generator(std::coroutine_handle<promise_type> h) : coro(h) {}
~Generator() { if (coro) coro.destroy(); }
bool next() {
coro.resume();
return !coro.done();
}
T value() { return coro.promise().current_value; }
};
// Fibonacci generator
Generator<int> fibonacci() {
int a = 0, b = 1;
while (true) {
co_yield a;
auto temp = a + b;
a = b;
b = temp;
}
}
// Usage
auto fib = fibonacci();
for (int i = 0; i < 10; ++i) {
fib.next();
std::cout << fib.value() << " ";
}
4. Modules
Modern replacement for header files.
// math.cppm (module interface)
module math;
export int add(int a, int b) {
return a + b;
}
export int multiply(int a, int b) {
return a * b;
}
// main.cpp
import math;
int main() {
int sum = add(3, 4);
int product = multiply(2, 5);
return 0;
}
// Partitioned modules
// math.cppm
export module math;
export int add(int a, int b);
// math_impl.cppm
module math:impl;
int add(int a, int b) {
return a + b;
}
5. Three-Way Comparison (Spaceship Operator)
#include <compare>
struct Point {
int x, y;
auto operator<=>(const Point& other) const = default;
// Generates: ==, !=, <, <=, >, >=
};
Point p1{1, 2};
Point p2{3, 4};
if (p1 < p2) { /* ... */ }
if (p1 == p2) { /* ... */ }
// Custom three-way comparison
struct Person {
std::string name;
int age;
auto operator<=>(const Person& other) const {
if (auto cmp = name <=> other.name; cmp != 0) {
return cmp;
}
return age <=> other.age;
}
};
6. consteval (Immediate Functions)
Functions that must be evaluated at compile time.
consteval int square(int x) {
return x * x;
}
constexpr int compile_time = square(5); // OK: computed at compile time
// int runtime = square(get_value()); // Error: must be compile-time
// Useful for compile-time computations
consteval int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
7. constinit
Initialize variables at compile time.
constinit int global_var = 42; // Must be compile-time initialized
void func() {
constinit static int local = 10; // Compile-time initialized
}
// Difference from constexpr
constexpr int must_be_constant = 42; // Immutable
constinit int can_be_modified = 42; // Can be modified later
8. Designated Initializers
Initialize struct members by name.
struct Point {
int x;
int y;
int z;
};
// C++20: designated initializers
Point p{.x = 10, .y = 20, .z = 30};
Point p2{.x = 5}; // y and z are zero-initialized
// Must be in declaration order
// Point p3{.y = 20, .x = 10}; // Error: wrong order
9. [[likely]] and [[unlikely]] Attributes
Hint branch prediction.
int process(int value) {
if (value > 0) [[likely]] {
return value * 2;
} else [[unlikely]] {
return 0;
}
}
// Switch cases
switch (value) {
case 0: [[likely]]
return 0;
case 1:
return 1;
default: [[unlikely]]
return -1;
}
10. Lambda Improvements
// Lambda with template parameters
auto lambda = []<typename T>(T value) {
return value * 2;
};
// Capture with initialization (C++14) + template
auto lambda2 = []<typename T>(T value) {
return [value]() { return value; };
};
// Default-constructible lambdas (C++20)
auto lambda3 = [](int x = 10) { return x; };
int result = lambda3(); // 10
11. requires Expressions
// Requires clause
template<typename T>
requires std::integral<T>
void func(T value) {}
// Requires expression
template<typename T>
concept Addable = requires(T a, T b) {
a + b; // Expression must be valid
{ a + b } -> std::convertible_to<T>; // With type requirement
};
// Compound requirements
template<typename T>
concept Swappable = requires(T& a, T& b) {
requires std::swappable<T>;
};
12. Class Template Argument Deduction Improvements
// Deduction guides
template<typename T>
class Container {
public:
Container(T value) : value_(value) {}
Container(T a, T b) : value_(value) {}
};
// Automatic deduction
Container c(42); // Container<int>
Container c2(1.0, 2.0); // Container<double>
Standard Library
13. Ranges Library
#include <ranges>
#include <vector>
#include <algorithm>
std::vector<int> vec = {1, 2, 3, 4, 5};
// Range concepts
static_assert(std::ranges::range<decltype(vec)>);
static_assert(std::ranges::sized_range<decltype(vec)>);
// Range algorithms
std::ranges::sort(vec);
auto it = std::ranges::find(vec, 3);
auto count = std::ranges::count_if(vec, [](int x) { return x > 3; });
// Range views
auto evens = vec | std::views::filter([](int x) { return x % 2 == 0; });
auto transformed = vec | std::views::transform([](int x) { return x * 2; });
14. std::format
Type-safe formatting.
#include <format>
std::string message = std::format("Hello, {}!", "World");
// "Hello, World!"
int x = 42;
double y = 3.14;
std::string result = std::format("x={}, y={:.2f}", x, y);
// "x=42, y=3.14"
// Format with positional arguments
std::string msg = std::format("{1} comes before {0}", "second", "first");
// "first comes before second"
15. std::jthread
Joinable thread with automatic joining.
#include <thread>
void worker() {
// Do work
}
// C++20: jthread automatically joins
std::jthread t(worker);
// No need to call t.join() - automatically joins on destruction
// With stop_token
void cancellable_worker(std::stop_token token) {
while (!token.stop_requested()) {
// Do work
}
}
std::jthread t2(cancellable_worker);
t2.request_stop(); // Request cancellation
16. std::span
Non-owning view of contiguous sequence.
#include <span>
int arr[] = {1, 2, 3, 4, 5};
std::vector<int> vec = {1, 2, 3, 4, 5};
// Create span
std::span<int> span1(arr, 5);
std::span<int> span2(vec);
// Subspan
auto subspan = span1.subspan(1, 3); // Elements 1-3
// Size and bounds checking
std::cout << span1.size() << std::endl;
std::cout << span1[0] << std::endl;
// Fixed-size span
std::span<int, 5> fixed_span(arr);
17. std::source_location
Source code location information.
#include <source_location>
void log(const std::string& message,
const std::source_location& location = std::source_location::current()) {
std::cout << location.file_name() << ":"
<< location.line() << ":"
<< location.function_name() << ": "
<< message << std::endl;
}
void func() {
log("Error occurred"); // Automatically captures location
}
18. Calendar and Timezone
#include <chrono>
using namespace std::chrono;
// Calendar types
auto date = year_month_day{2024y / January / 15d};
auto time = hh_mm_ss{14h + 30min + 45s};
// Timezone support
auto zoned = zoned_time{current_zone(), system_clock::now()};
auto utc = zoned_time{utc_clock::now()};
// Formatting
std::cout << std::format("{:%Y-%m-%d}", date) << std::endl;
19. std::bit_cast
Type-safe bit-level conversion.
#include <bit>
float f = 3.14f;
auto bits = std::bit_cast<uint32_t>(f); // Type-safe reinterpret_cast
// Safer than reinterpret_cast
// uint32_t bits2 = *reinterpret_cast<uint32_t*>(&f); // Undefined behavior
20. std::erase and std::erase_if
Erase elements from containers.
#include <vector>
#include <algorithm>
std::vector<int> vec = {1, 2, 3, 4, 5, 6};
// Erase by value
std::erase(vec, 3); // Removes all 3s
// Erase if
std::erase_if(vec, [](int x) { return x % 2 == 0; }); // Removes evens
Other Features
21. std::is_constant_evaluated()
Detect compile-time evaluation.
#include <type_traits>
constexpr int func(int x) {
if (std::is_constant_evaluated()) {
// Compile-time path
return x * 2;
} else {
// Runtime path
return x + 1;
}
}
constexpr int compile_time = func(5); // Uses compile-time path
int runtime = func(5); // Uses runtime path
22. std::to_array
Convert C array to std::array.
#include <array>
int arr[] = {1, 2, 3, 4, 5};
auto std_arr = std::to_array(arr); // std::array<int, 5>
23. std::make_shared for Arrays
#include <memory>
auto arr = std::make_shared<int[]>(10); // Shared array
arr[0] = 42;
Summary Table
| Feature | Category | Description |
|---|---|---|
| Concepts | Language | Named template requirements |
| Ranges | Library | Modern iteration |
| Coroutines | Language | Suspension/resumption |
| Modules | Language | Modern headers |
| Spaceship operator | Language | Three-way comparison |
consteval |
Language | Immediate functions |
constinit |
Language | Compile-time init |
| Designated init | Language | Named struct init |
[[likely]]/[[unlikely]] |
Language | Branch hints |
std::format |
Library | Type-safe formatting |
std::jthread |
Library | Auto-joining thread |
std::span |
Library | Array view |
std::source_location |
Library | Source info |
| Calendar/timezone | Library | Date/time utilities |
Migration Tips
- Use concepts instead of SFINAE
- Use ranges instead of iterator pairs
- Use
std::formatinstead ofprintf/sprintf - Use
std::spanfor array parameters - Use
std::jthreadinstead ofstd::thread - Use modules for new code
Compiler Support
- GCC: 10.0+ (most features), 11.0+ (full support)
- Clang: 10.0+ (most features), 12.0+ (full support)
- MSVC: Visual Studio 2019 16.8+ (most features), 16.10+ (full support)
Compile with: -std=c++20 (GCC/Clang) or /std:c++20 (MSVC)
C++20 was a revolutionary update that fundamentally changed how modern C++ is written, introducing concepts, ranges, coroutines, and modules.