Lesson 20 · 20 of 20
Project: a shopping cart · C++
Combine map, functions, references, exceptions, input and iomanip in C++ to build a shopping cart that prints its receipt.

The final project brings everything together in a shopping cart. The catalogue is a `std::map` from each product to its price: const because nobody should change it, and global, outside main, so any function can use it.
add takes the cart by reference so it can change it, the product as const std::string& and the units with a default value of 1. Before adding, it checks the data and, if something is wrong, throws std::invalid_argument with a clear message.
The orders are read from input.txt with while (std::cin >> item >> units), which stops when there are no more. Each order gets its own try: the caviar, which is not in the catalogue, and the cheese with no units are skipped with a warning, and the rest carry on. The last call, add(cart, "bread"), uses the default value.
cart[item] += units adds up: the two apple orders make 10. The receipt walks through the cart with a structured binding, [name, count], in alphabetical order, and `<iomanip>` lines up the columns with two decimals.
Finally, the ternary operator takes 10% off when the total is over 5 euros: 7.88 becomes 7.09. With an FLTK window instead of the console, this same logic would be a native desktop app in DMarlon Studio.
Code · main.cpp
#include <iomanip>#include <iostream>#include <map>#include <stdexcept>#include <string>const std::map<std::string, double> catalog = { {"apple", 0.35}, {"bread", 1.20}, {"cheese", 4.75}, {"milk", 0.99}};void add(std::map<std::string, int>& cart, const std::string& item, int units = 1) { if (catalog.count(item) == 0) throw std::invalid_argument("unknown product " + item); if (units <= 0) throw std::invalid_argument("no units of " + item); cart[item] += units;}int main() { std::map<std::string, int> cart; std::string item; int units = 0; // each order: product and units while (std::cin >> item >> units) { try { add(cart, item, units); } catch (const std::exception& e) { std::cout << "Skipped: " << e.what() << '\n'; } } add(cart, "bread"); // one unit by default std::cout << std::fixed << std::setprecision(2); double total = 0; for (const auto& [name, count] : cart) { double price = catalog.at(name); total += count * price; std::cout << std::left << std::setw(7) << name << std::right << std::setw(3) << count << " x" << std::setw(5) << price << std::setw(7) << count * price << '\n'; } std::cout << "Total " << total << ", to pay " << (total > 5 ? total * 0.90 : total) << '\n'; return 0;}Input (what gets typed) · input.txt
apple 6 milk 2 caviar 1 bread 1 cheese 0 apple 4
Output · c++ -std=c++17 main.cpp -o main && ./main
Skipped: unknown product caviar Skipped: no units of cheese apple 10 x 0.35 3.50 bread 2 x 1.20 2.40 milk 2 x 0.99 1.98 Total 7.88, to pay 7.09
Key points
- A constant
std::mapworks as a price list. - Pass by reference whatever the function must change.
- Check the data and throw an exception when it is wrong.
- One
tryper order: one error does not stop the rest. <iomanip>turns the data into a readable receipt.
Exercise
Also save the receipt to receipt.txt with a std::ofstream, and make add reject any order of more than 20 units by throwing an exception.