cppbest

Modern C++ features worth using, with small focused examples. Updated for C++20/23.

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