How to access contained value in C++23 std::optional without writing identity boilerplate?

Viewed 403

I am playing with C++23 std::optional additions, but I can not figure out how to elegantly access the value of object if optional is active.

I know I can use if, but that is so C++20.

I really like C++23 API changes, but I can not figure out how to skip the boilerplate of implementing identity. For example:

#include <functional>
#include <iostream>
#include <optional>

void print(std::optional<std::string>& name) {
    name.transform([](std::string& x) {
        std::cout << x << std::endl;
        // I just want to print, without modifying optional, but next line is required
        return x;
    });
}

int main() {
    std::optional<std::string> name{{"Bjarne"}};
    print(name);
}

It almost feels like std::optional is missing invoke member function.

note: in my example I do not chain anything else after transform, but that is for brevity, I care about optional not being modified.

1 Answers

The operations that were added to optional in C++23 are monadic in nature. That was the design of them. They fulfill certain common usage patterns that would otherwise be verbose and cumbersome to use. transform is for conditional transformations. and_then is for conditionally processing a whole new optional from an existing one. or_else is for cases where processing the lack of a value is pretty simplistic. And all of them work together to allow chaining.

But the basic act of "do something if the optional has a value" doesn't fit into this paradigm. It's not chainable. It's not monadic manipulation of the value. It's just normal use of an optional.

And doing it with if will not only be clearer as to what's going on, it'll have less noise (no lamdba and parameters, for example). There's just no reason to do that when the usual mechanism is just fine.

Related