Structured bindings C++17
Unpack pairs, tuples and array-like types directly into named variables — clearer than .first/.second.
// iterate a map without .first / .second
for (const auto& [key, value] : my_map) {
std::print("{} -> {}", key, value);
}
std::optional — maybe a value C++17
Express "no result" in the type system instead of sentinel values or output parameters.
std::optional<User> find_user(std::string_view name);
if (auto u = find_user("alice")) {
u->login();
} else {
// no such user: explicit, compiler-checked path
}
std::span — a non-owning view C++20
Pass "a sequence of T" to a function without caring whether it is a vector, array or buffer pointer.
std::size_t checksum(std::span<const std::byte> data);
std::array<std::byte, 4> a{};
std::vector<std::byte> v(64);
checksum(a); // both work,
checksum(v); // no pointers + sizes
Concepts — constraints on templates C++20
Readable requirements instead of substitution-failure walls of text.
template <typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
template <Numeric T>
T average(std::span<const T> v) {
return std::reduce(v.begin(), v.end(), T{}) / static_cast<T>(v.size());
}
Ranges — pipelines over collections C++20
Compose transformations and filters lazily, no intermediate vectors.
auto names = students
| std::views::filter(&Student::active)
| std::views::transform(&Student::name)
| std::views::take(10);
std::format / std::print C++20/23
Type-safe, extensible formatting; std::print also removes the classic iostream boilerplate.
std::print("Hello, {}! You have {} messages.\n", user, count);
std::println("{:.2f} GiB", bytes / 1024.0 / 1024.0 / 1024.0);
constexpr and consteval computation C++20
Move table generation and validation to compile time; consteval guarantees it.
consteval std::array<int, 10> squares() {
std::array<int, 10> out{};
for (int i = 0; i < 10; ++i) out[i] = i * i;
return out;
}
constexpr auto table = squares(); // zero runtime cost
Three-way comparison, the spaceship C++20
One line gives you ==, < and friends with correct semantics.
struct Version {
int major, minor, patch;
auto operator<=>(const Version&) const = default;
};
static_assert(Version{1,2,0} < Version{1,10,0});
Smart pointers & RAII by default core
Ownership expressed in types: unique_ptr for exclusive, shared_ptr when sharing is real, raw pointers/views only for borrowing.
auto node = std::make_unique<Node>(args...); // exclusive owner tree.attach(std::move(node)); // ownership moved void observe(const Node& n); // borrowing: no pointer churn
Further reading
cppreference — C++ reference · ISO C++ FAQ · modern-cpp-features on GitHub