将一个 std::optional 转换为另一个 std::optional

Pat*_*ick 3 c++ stdoptional

我有一个返回可选结构的方法,如下所示:

auto getBook(const std::string &title) const -> std::optional<Book>;
Run Code Online (Sandbox Code Playgroud)

我想在另一个返回可选作者的方法中调用此方法。问题在于,在调用方法之前,实现应该始终检查 getBook 返回的可选值是否已填充,如下所示:

auto getAuthor(const std::string &title) const -> std::optional<Author>
{
   const auto optBook = getBook(title);
   if (optBook.has_value)
      return optBook->getAuthor();
   else
      return std::nullopt;
}
Run Code Online (Sandbox Code Playgroud)

有没有办法以更短的方式编写它,以便如果填充了可选项,则调用该方法,但如果可选项为空,std::nullopt则返回。像这样的东西(我知道这目前不起作用,但你明白我的意思):

auto getAuthor(const std::string &title) const -> std::optional<Author>
{
   return getBook(title).getAuthor();
}
Run Code Online (Sandbox Code Playgroud)

Vit*_*meo 8

您可以通过创建一个map函数来概括此模式,该函数接受一个 optionalo和一个 function f,并返回f(*o)if的结果o.has_value() == true

template <typename O, typename F>
auto map(O&& o, F&& f) -> std::optional<decltype(f(*std::forward<O>(o)))>
{
    if (!o.has_value()) 
    {
        return {std::nullopt};
    }

    return {f(*std::forward<O>(o))};
}
Run Code Online (Sandbox Code Playgroud)

然后您可以定义getAuthor为:

auto getAuthor(const std::string& title) -> std::optional<Author>
{
    return map(getBook(title), [](Book b)
    {
        return b.author;
    });
}
Run Code Online (Sandbox Code Playgroud)

Godbolt.org 上的现场示例


我为这类操作创建了一个库,名为scelta. 使用我的库,您可以编写:

auto getBook(const std::string& title) -> std::optional<Book>;
auto getAuthor(const std::optional<Book>& title) -> std::optional<Author>;

using namespace scelta::infix;
std::optional<Author> a = getBook("...") | map(getAuthor);
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅“Monadic 可选操作”