diff --git a/lectures/optional_and_variant.md b/lectures/optional_and_variant.md new file mode 100644 index 0000000..27285fc --- /dev/null +++ b/lectures/optional_and_variant.md @@ -0,0 +1,144 @@ + +**`std::optional` and `std::variant` in Modern C++** +-- + +

+ Video Thumbnail +

+ +## **Introduction** + +When working with modern C++ (C++17 and beyond), we often need tools to handle optional values or represent data that can take one of several types. That’s where `std::optional` and `std::variant` come into play. Today, we’ll explore what these features are, why they’re useful, and how you can leverage them in your projects. + + +## **What is `std::optional`?** + +### Why use `std::optional`? + +Imagine a function that searches for an item in a container. If the item is found, the function should return it. But what if it isn’t? Before C++17, you might have returned a special value (like `-1` for integers) or used a pointer, potentially introducing ambiguity or risking undefined behavior. + +`std::optional` solves this by explicitly representing the absence of a value. It's a type-safe mechanism that avoids the pitfalls of ad-hoc solutions. + +### Examples of `std::optional` in action + +#### A simple search function + +````cpp +#include +#include +#include + +std::optional Find(const std::vector& data, int value) { + for (int element : data) { + if (element == value) { + return element; // Return the value if found + } + } + return std::nullopt; // Explicitly indicate "no value" +} + +int main() { + std::vector numbers = {1, 2, 3, 4, 5}; + auto result = Find(numbers, 3); + + if (result) { // Check if a value exists + std::cout << "Found: " << *result << '\n'; + } else { + std::cout << "Not found.\n"; + } +} +```` +In this example, `std::optional` clearly communicates that the function may or may not return a value. + +#### A factory function + +````cpp +std::optional CreateString(bool should_create) { + if (should_create) { + return "Hello, World!"; + } + return std::nullopt; +} + +int main() { + auto maybe_string = CreateString(true); + + if (maybe_string) { + std::cout << *maybe_string << '\n'; + } else { + std::cout << "No string created.\n"; + } +} +```` +--- + +## **What is `std::variant`?** + +### Why use `std::variant`? + +`std::variant` is a type-safe union introduced in C++17. It allows a variable to hold one value out of a defined set of types. Think of it as a more flexible alternative to `enum` or `std::any`, but with static type checking. + +For instance, if a variable can hold either an integer or a string, you can use `std::variant` instead of rolling your own solution with `void*` or `boost::variant`. + +### Examples of `std::variant` in action + +#### Basic usage + +````cpp +#include +#include +#include + +int main() { + std::variant value; + + value = 42; // Assign an integer + std::cout << "Integer: " << std::get(value) << '\n'; + + value = "Hello, std::variant!"; // Assign a string + std::cout << "String: " << std::get(value) << '\n'; +} +```` +#### Pattern matching with `std::visit` + +````cpp +#include +#include +#include + +int main() { + std::variant value = "Hello, Variant!"; + + std::visit([](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + std::cout << "Integer: " << arg << '\n'; + } else if constexpr (std::is_same_v) { + std::cout << "String: " << arg << '\n'; + } + }, value); +} +```` +Here, `std::visit` applies a visitor (a callable object) to the value contained in the variant. + +--- + +## **Key differences and common use cases** + +| Feature | `std::optional` | `std::variant` | +|--------------------|------------------------------------------------------|------------------------------------------------| +| Purpose | Represents optional values (may or may not exist). | Represents one of several types. | +| Typical Use Case | Returning a value or "nothing" from a function. | Handling inputs or data with multiple types. | +| Type Safety | Yes. | Yes. | +| Pattern Matching | Not applicable. | Supported via `std::visit`. | + +--- + +## **Summary** + +`std::optional` and `std::variant` are two powerful tools in the C++ toolbox that greatly enhance type safety and code readability. + +- Use `std::optional` when a value might be absent. +- Use `std::variant` when a value can be one of several types. + +These features enable us to write cleaner, more expressive code while avoiding common pitfalls. Experiment with them in your projects and see how they can simplify your development workflow!