Modules and Coroutines

Modules and Coroutines

A fast reference to two major C++20 features that need deliberate adoption.

Modules and Coroutines

Modules

export module math;

export int add(int a, int b) {
    return a + b;
}
import math;

Typical module split

export module math;

export int add(int a, int b);
module math;

int add(int a, int b) {
    return a + b;
}

Keep the interface unit small and stable. Move implementation details out of the exported surface when possible.

Practical module advice

Minimal build shape

add_library(math)
target_sources(math
    PUBLIC
        FILE_SET CXX_MODULES FILES math.cppm
    PRIVATE
        math.cpp
)

The key reminder is that module adoption is a build-model change, not just a syntax change.

Coroutines

generator<int> countdown(int from) {
    while (from > 0) {
        co_yield from--;
    }
}

Minimal async shape

task<int> compute() {
    int base = co_await read_value_async();
    co_return base * 2;
}

Even this tiny example shows the real coroutine value: the code reads top-to-bottom while still modeling suspension.

Coroutine mental model

Adoption guidance

Quick adoption checklist

When modules help most

When coroutines help most

Reality check

Quick decision rule

One-line patterns to remember

Example in practice

// math.cppm
    export module math;
    export int add(int a, int b);

    // main.cpp
    import math;
    int main() { return add(2, 3); }

Try this variation

Swap one older pattern for a newer standard facility, then compare clarity. This keeps modern C++ grounded in practical tradeoffs instead of feature tourism.

#include <format>
#include <string>

int main() {
    std::string line = std::format("{} items ready", 3);
    return static_cast<int>(line.size());
}