Monadic operations with std::optional

Can you explain and provide examples of the monadic operations available for std::optional in C++23?

In C++23, std::optional introduces support for monadic operations. These operations allow you to work with optional values in a more functional way, enabling you to chain operations together and handle empty optionals gracefully. The main monadic operations are and_then, or_else, and transform.

and_then()

This operation allows you to chain optional-producing operations. If the optional has a value, and_then applies the given function to the value, which should return another optional. If the original optional is empty, and_then returns an empty optional.

#include <iostream>
#include <optional>

std::optional<int> square(int x) {
  return x * x;
}

int main() {
  std::optional<int> maybe_int = 10;
  auto result = maybe_int.and_then(square);
  if (result) {
    std::cout << "Result: " << *result << '\n';
  }

  maybe_int = std::nullopt;
  result = maybe_int.and_then(square);
  if (!result) {
    std::cout << "Result is empty" << '\n';
  }
}

This will output:

Result: 100
Result is empty

or_else()

This operation allows you to provide an alternative optional value if the original optional is empty. If the original optional has a value, or_else returns it. If the original optional is empty, or_else returns the result of the given function, which should return another optional.

#include <iostream>
#include <optional>

std::optional<int> get_default() { return 42; }

int main() {
  std::optional<int> maybe_int = 10;
  auto result = maybe_int.or_else(get_default);
  std::cout << "Result: " << *result << '\n';

  maybe_int = std::nullopt;
  result = maybe_int.or_else(get_default);
  std::cout << "Result: " << *result << '\n';
}

This will output:

Result: 10
Result: 42

transform()

This operation allows you to apply a function to the value in an optional, if it exists. If the optional is empty, transform returns an empty optional.

#include <iostream>
#include <optional>

int square(int x) { return x * x; }

int main() {
  std::optional<int> maybe_int = 10;
  auto result = maybe_int.transform(square);
  if (result) {
    std::cout << "Result: " << *result << '\n';
  }

  maybe_int = std::nullopt;
  result = maybe_int.transform(square);
  if (!result) {
    std::cout << "Result is empty" << '\n';
  }
}

This will output:

Result: 100
Result is empty

These monadic operations make it easier to work with std::optional in a functional style, allowing you to chain operations and handle empty optionals in a clear and concise way.

Nullable Values, std::optional and Monadic Operations

A comprehensive guide to using std::optional to represent values that may or may not be present.

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

When should I use std::optional in C++?
In what situations is it appropriate to use std::optional instead of just regular values or pointers?
std::optional vs pointers in C++
When should I use std::optional instead of a pointer in C++? What are the differences?
Accessing the value in a std::optional
What is the best way to access the value stored in a std::optional? When should I use value() vs operator*?
Using std::optional for class members
How can I use std::optional for members in my C++ classes? Can you provide an example?
Checking if a std::optional has a value
What are the different ways to check if a std::optional contains a value?
Using std::optional as a return type
When is it appropriate to use std::optional as a return type for a function?
Performance considerations with std::optional
Are there any performance considerations to keep in mind when using std::optional?
Using std::optional with pointers
Can std::optional be used with pointers? If so, how?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant