Key Features Introduced in C++20
C++20 significantly modernizes the language with several major additions that enhance expressiveness, safety, and performance.
Concepts enable constraints on template parameters, improving compile-time error messaegs and code clarity:
#include <concepts>
template <std::integral T>
T sum(T a, T b) {
return a + b;
}
int main() {
auto res = sum(10, 20); // OK: int satisfies std::integral
// sum(3.14, 2.71); // Error: double does not satisfy std::integral
}
Ranges simplify sequence processing by composing views and algorithms lazily:
#include <vector>
#include <ranges>
#include <iostream>
int main() {
std::vector<int> vals = {1, 2, 3, 4, 5, 6};
auto evens = vals | std::views::filter([](int n) { return n % 2 == 0; });
for (int v : evens) {
std::cout << v << ' ';
}
}
Coroutines support suspendable functions, ideal for generators and asynchronous workflows:
#include <coroutine>
#include <iostream>
struct NumberGenerator {
struct promise_type {
int val_;
NumberGenerator get_return_object() {
return { std::coroutine_handle<promise_type>::from_promise(*this) };
}
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
std::suspend_always yield_value(int v) { val_ = v; return {}; }
void unhandled_exception() {}
};
explicit NumberGenerator(std::coroutine_handle<promise_type> h) : handle_(h) {}
~NumberGenerator() { if (handle_) handle_.destroy(); }
bool next() { handle_.resume(); return !handle_.done(); }
int value() const { return handle_.promise().val_; }
private:
std::coroutine_handle<promise_type> handle_;
};
NumberGenerator range(int start, int end) {
for (int i = start; i <= end; ++i)
co_yield i;
}
int main() {
auto gen = range(1, 3);
while (gen.next()) {
std::cout << gen.value() << ' ';
}
}
Modules replace header files to improve compilation speed and encapsulation:
// math.mpp
export module math;
export int multiply(int a, int b) { return a * b; }
// main.cpp
import math;
int main() { return multiply(6, 7); }
Designated initializers allow clearer aggregate initialization:
struct Vec3 { double x, y, z; };
Vec3 v{.x = 1.0, .y = 2.0, .z = 3.0};
Three-way comparison (<=>) enables concise relational operator definitions:
struct Point { int x, y; auto operator<=>(const Point&) const = default; };
Enhanced constexpr now supports dynamic allocation and virtual calls in constant expressions:
constexpr int factorial(int n) {
return (n <= 1) ? 1 : n * factorial(n - 1);
}
static_assert(factorial(5) == 120);
New standard library components include:
std::span: non-owning view over contiguous memory:
#include <span>
void process(std::span<const int> data) { /* ... */ }
std::jthread: automatically joins and supports cooperative cancellation:
#include <thread>
std::jthread worker([](std::stop_token st) {
while (!st.stop_requested()) { /* work */ }
});
std::format: safe, extensible formatting:
#include <format>
std::cout << std::format("Value: {}\n", 42);
- Chrono enhancements: calendar types and time zone support (partial in C++20).
Lambda improvements include:
- Template-like syntax with
autoparameters:
auto add = [](auto a, auto b) { return a + b; };
- Initialization in captures:
int base = 5;
auto f = [offset = base + 1] { return offset; };
constexprlambdas:
constexpr auto square = [](int x) { return x * x; };
Additional features like consteval, improved aggregate handling, and stricter type checking further refine the language.