// sample-program.cpp: a small, complete C++20 program with numbered comments. // Free sample from 99helpers.com/file-types/cpp // // It prints a stock report for a few fictional shop items, sorted by value. // // Build and run on Linux or macOS (a recent GCC or Clang): // c++ -Wall -Wextra -std=c++20 sample-program.cpp -o sample-program // ./sample-program // On Windows with Microsoft's compiler, in a Developer Command Prompt: // cl /W4 /EHsc /std:c++20 sample-program.cpp // sample-program.exe // 1. Includes: C++ standard headers have no .h extension. Each one brings in // a part of the standard library, all inside the std namespace. #include #include #include #include #include #include #include #include #include #include #include #include #include // 2. A namespace keeps our names apart from everyone else's: this class is // shop::Item, so it can't collide with an Item in a library. namespace shop { // 3. A class: private data, a constructor that checks its input, and const // member functions that promise not to change the object. class Item { public: Item(std::string name, int stock, double price) : name_{std::move(name)}, stock_{stock}, price_{price} { if (stock < 0) { throw std::invalid_argument{"stock cannot be negative: " + name_}; } } const std::string& name() const { return name_; } int stock() const { return stock_; } double price() const { return price_; } double value() const { return stock_ * price_; } private: std::string name_; int stock_; double price_; }; // 4. A function template, constrained with a C++20 concept: it accepts a // vector of any floating-point type, and nothing else. template T total(const std::vector& values) { return std::accumulate(values.begin(), values.end(), T{0}); } // 5. std::optional: a return value that may be missing, instead of a null // pointer or a magic value such as -1. std::optional find(const std::vector& items, std::string_view name) { for (const auto& item : items) { if (item.name() == name) { return item; } } return std::nullopt; } } // namespace shop int main() { // 6. A std::vector owns its items. When it goes out of scope it frees // their memory itself (RAII), so there is no delete or free anywhere. std::vector items{ {"Notebook", 12, 3.50}, {"Pencil", 40, 0.80}, {"Stapler", 2, 7.25}, {"Ruler", 0, 1.20}, {"Glue stick", 5, 1.95}, }; // 7. An algorithm from : sort by value, largest first. // std::ranges::sort takes the whole vector and a projection. std::ranges::sort(items, std::greater{}, &shop::Item::value); // 8. A range-based for loop and stream formatting with . std::cout << std::fixed << std::setprecision(2); std::vector values; for (const auto& item : items) { std::cout << std::left << std::setw(12) << item.name() << std::right << std::setw(5) << item.stock() << std::setw(8) << item.price() << std::setw(9) << item.value() << '\n'; values.push_back(item.value()); } std::cout << "Total stock value: " << shop::total(values) << '\n'; // 9. A lambda (an unnamed function) and a std::map, which keeps its keys // sorted: here, how many items fall in each stock level. auto level = [](const shop::Item& item) { return item.stock() == 0 ? "out" : item.stock() < 5 ? "low" : "ok"; }; std::map levels; for (const auto& item : items) { ++levels[level(item)]; } for (const auto& [name, count] : levels) { // structured bindings std::cout << name << ": " << count << '\n'; } // 10. Using the optional: test it before reading the value. if (auto found = shop::find(items, "Pencil")) { std::cout << "Found " << found->name() << " at " << found->price() << '\n'; } // 11. Exceptions: the constructor throws, the catch block handles it, // and the program carries on. try { shop::Item broken{"Eraser", -3, 0.50}; } catch (const std::invalid_argument& error) { std::cout << "Rejected: " << error.what() << '\n'; } return 0; // 12. Exit status 0 means success (main may also omit it). }