C++20: Concepts, Ranges, Coroutines

C++20 — concepts, ranges, coroutines

Read: ~40 min 14 practice problems

1. Concepts — Constrained Templates

Concepts state requirements on template parameters. Errors become readable, intent becomes clear.

concepts.cpp
#include <iostream>
#include <concepts>

template<std::integral T>
T square(T x) { return x * x; }

template<typename T>
concept Addable = requires(T a, T b) { a + b; };

template<Addable T>
T add(T a, T b) { return a + b; }

int main() {
    std::cout << square(5) << "\n";
    // square(5.0); // ERROR: not integral, clean diagnostic!
    std::cout << add(3, 4) << "\n";
}

2. Ranges & Pipe Syntax

ranges.cpp
#include <iostream>
#include <vector>
#include <ranges>

int main() {
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8};

    auto view = v
        | std::views::filter([](int x){ return x % 2 == 0; })
        | std::views::transform([](int x){ return x * x; });

    for (int x : view) std::cout << x << " ";
    // 4 16 36 64
}

Views are lazy and composable — like Unix pipes for data.

3. Spaceship <=>

Default all 6 comparison operators in one line:

space.cpp
struct Point {
    int x, y;
    auto operator<=>(const Point&) const = default;
};
// Now Point supports <, <=, >, >=, ==, != !

4. Coroutines (Brief)

Functions that can suspend and resume. Core C++20 syntax: co_await, co_yield, co_return. Powerful but currently library-heavy — most users wait for community libraries to mature.

5. Modules (Brief)

Replacement for headers — faster compiles, better encapsulation. Adoption is gradual; major compilers and build systems are still maturing support. Worth watching for new projects starting in 2026.

math.ixx
export module math;
export int square(int x) { return x * x; }

6. Practice Problems

  1. Constrain T to be floating-point.
    ✨ Show Answer
    template<std::floating_point T>
    T f(T x) { ... }
  2. Define a Comparable concept.
    ✨ Show Answer
    template<typename T>
    concept Comparable = requires(T a, T b) { { a < b } -> std::convertible_to<bool>; };
  3. Pipe: take first 3 squares of even numbers.
    ✨ Show Answer
    auto r = v | std::views::filter(even)
                | std::views::transform([](int x){ return x*x; })
                | std::views::take(3);
  4. Are ranges eager or lazy?
    ✨ Show Answer

    Lazy. Views compute on demand. No intermediate vectors are built.

  5. Default all comparisons for a struct.
    ✨ Show Answer
    auto operator<=>(const X&) const = default;
  6. Why are concepts more readable than SFINAE?
    ✨ Show Answer

    Constraints stated up front, errors point at the violated requirement, intent is documented.

  7. Convert range view to vector.
    ✨ Show Answer
    auto v = view | std::ranges::to<std::vector>(); // C++23
  8. Iota a range of 1..10.
    ✨ Show Answer
    for (int i : std::views::iota(1, 11)) ...
  9. Use a concept inline with auto.
    ✨ Show Answer
    void f(std::integral auto x) { ... }
  10. What returns the spaceship operator?
    ✨ Show Answer

    An ordering type — std::strong_ordering for ints, std::partial_ordering for floats, etc.

  11. Why might modules speed up compilation?
    ✨ Show Answer

    Modules are compiled once and cached. Headers are textually re-parsed for every translation unit that includes them.

  12. A coroutine that yields squares.
    ✨ Show Answer

    Conceptual: generator<int> squares() { for (int i = 1;; ++i) co_yield i*i; } — needs a generator type from a library.

  13. requires expression for a type with size().
    ✨ Show Answer
    template<typename T>
    concept Sized = requires(T t) { { t.size() } -> std::convertible_to<size_t>; };
  14. Why do error messages get cleaner with concepts?
    ✨ Show Answer

    Compiler checks the concept first and reports the specific requirement that failed, not buried instantiation errors deep in template internals.

Summary

C++20 brings concepts (constrained templates with clean errors), ranges (lazy, pipe-composable views), coroutines, modules, and the spaceship operator. These are the biggest leap since C++11 — start using concepts and ranges in new code today.

Next Module → Multithreading: std::thread, mutex, async.