std::optional::and_then(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– NAME πŸ’–

hey bestie, welcome to std::optional::and_then(3) from the C++ Standard Libary manual β€” yes, that’s the exact spelling, and we’re keeping it πŸ’…

std::optional::and_then β€” std::optional::and_then


✨ Synopsis ✨

          template< class F >                       (1) (since C++23)
          constexpr auto and_then( F&& f ) &;
          template< class F >                       (2) (since C++23)
          constexpr auto and_then( F&& f ) const&;
          template< class F >                       (3) (since C++23)
          constexpr auto and_then( F&& f ) &&;
          template< class F >                       (4) (since C++23)
          constexpr auto and_then( F&& f ) const&&;

okay so the vibe is: if *this contains a value, it invokes f with the contained value as an argument, and returns the result of that invocation; otherwise, it returns an empty std::optional. 🫢

and listen β€” the return type (see below) must be a specialization of std::optional (unlike transform()). otherwise, the program is ill-formed. no cap, that part is not flexible. 😭

1) Equivalent to

        if (*this)
            return std::invoke(std::forward<F>(f), **this);
        else
            return std::remove_cvref_t<std::invoke_result_t<F, T&>>{};

2) Equivalent to

        if (*this)
            return std::invoke(std::forward<F>(f), **this);
        else
            return std::remove_cvref_t<std::invoke_result_t<F, const T&>>{};

3) Equivalent to

        if (*this)
            return std::invoke(std::forward<F>(f), std::move(**this));
        else
            return std::remove_cvref_t<std::invoke_result_t<F, T>>{};

4) Equivalent to

        if (*this)
            return std::invoke(std::forward<F>(f), std::move(**this));
        else
            return std::remove_cvref_t<std::invoke_result_t<F, const T>>{};

🌸 Parameters 🌸

  • f β€” a suitable function or Callable object that returns an std::optional πŸ’–

πŸŽ€ Return value πŸŽ€

the result of f or an empty std::optional, as described above. iconique. ✨


πŸ¦‹ Notes πŸ¦‹

some languages call this operation flatmap. it’s giving β€œflatmap but make it std::optional” fr fr.

feature-test macro vibe check: __cpp_lib_optional has value 202110L, in (C++23), for the feature Monadic operations in std::optional. πŸ‘‘


πŸ”₯ Example πŸ”₯

        // Run this code

        #include <charconv>
        #include <iomanip>
        #include <iostream>
        #include <optional>
        #include <ranges>
        #include <string>
        #include <string_view>
        #include <vector>

        std::optional<int> to_int(std::string_view sv)
        {
            int r{};
            auto [ptr, ec]{std::from_chars(sv.data(), sv.data() + sv.size(),
       r)};
            if (ec == std::errc())
                return r;
            else
                return std::nullopt;
        }

        int main()
        {
            using namespace std::literals;

            const std::vector<std::optional<std::string>> v
            {
                "1234", "15 foo", "bar", "42", "5000000000", " 5",
       std::nullopt, "-43"
            };

            for (auto&& x : v | std::views::transform(
                [](auto&& o)
                {
                    // debug print the content of input optional<string>
                    std::cout << std::left << std::setw(13)
                              << std::quoted(o.value_or("nullopt")) << " -> ";

                    return o
                        // if optional is nullopt convert it to optional with
       "" string
                        .or_else([]{ return std::optional{""s}; })
                        // flatmap from strings to ints (making empty optionals
       where it fails)
                        .and_then(to_int)
                        // map int to int + 1
                        .transform([](int n) { return n + 1; })
                        // convert back to strings
                        .transform([](int n) { return std::to_string(n); })
                        // replace all empty optionals that were left by
                        // and_then and ignored by transforms with "NaN"
                        .value_or("NaN"s);
                }))
                std::cout << x << '\n';
        }

πŸ“ Output πŸ“

        "1234"        -> 1235
        "15 foo"      -> 16
        "bar"         -> NaN
        "42"          -> 43
        "5000000000"  -> NaN
        " 5"          -> NaN
        "nullopt"     -> NaN
        "-43"         -> -42

πŸ‘‘ See also πŸ‘‘

  • value_or β€” returns the contained value if available, another value otherwise (public member function)
  • transform β€” returns an optional containing the transformed contained value if it exists, or an empty optional otherwise (C++23) (public member function)
  • or_else β€” returns the optional itself if it contains a value, or the result of the given function otherwise (C++23) (public member function)

mwah πŸ’‹ β€” this cutie came from cppreference.com, dated 2024.06.10, and yes bestie it’s still std::optional::and_then(3). slay. 🫢🌈

πŸ“¦ where this page comes from