C/C++ Arena

Step 1 of 7

Strategies as closures

A design pattern is a named, well-tested solution to a problem that keeps coming up. Knowing the names helps you recognize them in large codebases and talk about designs with other programmers. This module shows the ones you'll meet most, written the modern C++ way.

The Strategy pattern swaps an algorithm at run time: how to sort, how to price, how to compress. The textbook version uses an abstract base class with one subclass per strategy. When a strategy is a single function, modern C++ just uses std::function, and a function that returns a lambda builds configured strategies:

#include <functional>
#include <iostream>
#include <string>
#include <vector>

using Shipping = std::function<double(double weight_kg)>;

Shipping flat_rate(double price) {
    return [price](double) { return price; };
}

Shipping per_kg(double rate, double minimum) {
    return [rate, minimum](double kg) {
        double cost = kg * rate;
        return cost < minimum ? minimum : cost;
    };
}

int main() {
    std::vector<std::pair<std::string, Shipping>> options = {
        {"standard", per_kg(1.5, 4.0)},
        {"express", flat_rate(12.0)},
    };
    for (double kg : {1.0, 10.0}) {
        for (const auto& [name, cost] : options) {
            std::cout << kg << "kg " << name << ": " << cost(kg) << "\n";
        }
    }
}
1kg standard: 4
1kg express: 12
10kg standard: 15
10kg express: 12

Closures

Each lambda captures its settings (price, or rate and minimum), so every returned strategy remembers its own configuration after the factory function has returned. A lambda together with its captured values is called a closure. per_kg(1.5, 4.0) and per_kg(2.0, 5.0) are two independent strategies made by the same code.

Your task

Your task

Write the strategy factories percent_off(pct) and flat_off(amount) (never below 0), and Cart::total(), which sums the prices and applies the cart's discount strategy once to the sum.

Challenge 2

Small strategies can be combined into bigger ones. Rule is a std::function<bool(int)>. Write the factories at_least(n) and at_most(n), and the combinators both(a, b) (true when both rules pass) and negate(r).

Challenge 3

Write class Pipeline, a list of text transformations run in order. add(step) takes a std::function<std::string(std::string)> and returns *this so calls can be chained. run(input) passes the input through every step. Also write the factory prefix(p), a step that puts p in front.

Next: A factory registry