std::optional::and_then în C++

Înlănțuiește operații pe un optional: and_then și transform rulează funcția doar dacă există valoare.

Sintaxă
template<class F> constexpr auto and_then(F&& f);    // f returnează std::optional<U>
template<class F> constexpr auto transform(F&& f);   // f returnează U

Ce face std::optional::and_then

Cele două metode evită șirurile de if (o). Dacă optional-ul este gol, rezultatul este tot gol și funcția nu se apelează.

o.transform(f) aplică f pe valoare și pune rezultatul într-un optional nou (de exemplu din optional<string> obții optional<size_t>). o.and_then(f) se folosește când f poate eșua și returnează ea însăși un optional; rezultatul nu mai este împachetat încă o dată.

Mai există or_else(f), care rulează f doar când optional-ul este gol.

Parametri

Parametru Descriere
f Funcția (de obicei o lambda) aplicată pe valoare.

Ce returnează

Un std::optional nou: gol dacă originalul era gol, altfel rezultatul lui f.

Exemple

Exemplul 1: Citirea unei vârste dintr-un text

Fiecare pas poate eșua; dacă unul eșuează, restul lanțului este sărit.

#include <charconv>
#include <format>
#include <optional>
#include <print>
#include <string>

std::optional<int> numar(const std::string& s) {
    int n{};
    auto [p, ec] = std::from_chars(s.data(), s.data() + s.size(), n);
    if (ec != std::errc{} || p != s.data() + s.size()) return std::nullopt;
    return n;
}

std::optional<int> varstaValida(int v) {
    if (v < 0 || v > 120) return std::nullopt;
    return v;
}

int main() {
    for (std::string text : {"34", "abc", "250"}) {
        auto mesaj = numar(text)
            .and_then(varstaValida)
            .transform([](int v) { return std::format("{} ani", v); })
            .value_or("vârstă invalidă");
        std::println("{:>3} -> {}", text, mesaj);
    }
}

Rezultat

 34 -> 34 ani
abc -> vârstă invalidă
250 -> vârstă invalidă

Exemplul 2: transform: lungimea unui nume opțional

#include <optional>
#include <print>
#include <string>

int main() {
    std::optional<std::string> nume = "Alexandra";
    std::optional<std::string> lipsa;

    auto lungime = [](const std::string& s) { return s.size(); };
    std::println("{}", nume.transform(lungime).value_or(0));
    std::println("{}", lipsa.transform(lungime).value_or(0));
}

Rezultat

9
0

Greșeli frecvente

  • Folosești transform cu o funcție care returnează un optional. Obții optional<optional<T>>; pentru astfel de funcții se folosește and_then.

Comenzi înrudite

  • std::optional: O valoare care poate lipsi: conține fie un obiect de tip T, fie nimic (std::nullopt).
  • std::optional::value: value() citește valoarea și aruncă excepție dacă optional e gol; value_or() dă o valoare implicită.
  • std::expected: Rezultatul unei operații care poate eșua: conține fie valoarea (T), fie motivul erorii (E).
  • lambda ([](){}): O funcție fără nume, scrisă direct acolo unde e folosită; poate „captura” variabile din jur.