c++ - C++ 中的链 optional

标签 c++ optional c++17

如何避免在 C++ 中使用链式选项嵌套 if 语句?

例如,如果类型 A 包含 std::optional<B> b和 B 型 std::optional<C> c ,我希望能够写出类似的东西:

const auto v = if_exists(if_exists(a->b)->c);

如果 b 或 c 是空 optional 项,则 v 将从 c 或空 optional 项中获取值。

我认为这样嵌套 ifs 会更好:
if (a->b) {
 const auto b = *(a->b);
 if (b->c) {
  const auto c = *(b->c);
 }
}

以下问题似乎朝这个方向发展,但我不确定如何使其适应我的用例:Haskell style "Maybe" type & *chaining* in C++11

最佳答案

你可能会用

template <typename T, typename F>
auto convert_optional(const std::optional<T>& o, F&& f)
-> std::optional<std::decay_t<decltype(std::invoke(std::forward<F>(f), *o))>>
{
    if (o)
        return std::invoke(std::forward<F>(f), *o);
    else
        return std::nullopt;
}

template <typename T, typename F>
auto convert_optional(std::optional<T>& o, F&& f)
-> std::optional<std::decay_t<decltype(std::invoke(std::forward<F>(f), *o))>>
{
    if (o)
        return std::invoke(std::forward<F>(f), *o);
    else
        return std::nullopt;
}

template <typename T, typename F>
auto convert_optional(std::optional<T>&& o, F&& f)
-> std::optional<std::decay_t<decltype(std::invoke(std::forward<F>(f), *std::move(o)))>>
{
    if (o)
        return std::invoke(std::forward<F>(f), *std::move(o));
    else
        return std::nullopt;
}

或者
template <typename> struct is_optional : std::false_type {};
template <typename T> struct is_optional<std::optional<T>> : std::true_type {};

template <typename O, typename F>
auto convert_optional(O&& o, F&& f)
-> std::enable_if_t<
    is_optional<std::decay_t<O>>::value,
    std::optional<std::decay_t<decltype(std::invoke(std::forward<F>(f),
                                                    *std::forward<O>(o)))>>>
{
    if (o)
        return std::invoke(std::forward<F>(f), *o);
    else
        return std::nullopt;
}

你的例子变成:
auto c = convert_optional(convert_optional(a, &A::b).value_or(std::nullopt),
                          &B::c).value_or(std::nullopt);
convert_optional(a, &A::b)将返回 std::optional<std::optional<B>>
您甚至可以通过附加功能来简化:
template <typename O, typename F>
auto convert_optional_fact(O&& o, F&& f)
-> decltype(convert_optional(std::forward<O>(o),
                             std::forward<F>(f)).value_or(std::nullopt))
{
    return convert_optional(std::forward<O>(o),
                            std::forward<F>(f)).value_or(std::nullopt);
}

进而
auto c = convert_optional_fact(convert_optional_fact(a, &A::b), &B::c);

Demo

关于c++ - C++ 中的链 optional ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48905531/

相关文章:

scala - 为什么 "flatMap"在 Scala 中使用 Option 类型的序列?

java-8 - 为什么在 Java 8 中有多个版本的 Optional

c++ - 即使 XZY 具有非复制约束,构造助手 make_XYZ 也允许 RVO 和类型推导

c++ - 如何将Std::set_terminate与SetUnhandledExceptionFilter一起使用?

c++ - 定义不删除指针的最干净的方法是什么?

c++ - 无法使用 get 函数返回对象数组

c++ - 指向非指针编译错误的唯一指针

python - Boost python,从另一个类的方法返回一个类

c++ - std::optional:不参与重载决议与被定义为已删除

c++ - 如何使用 std::copy 将一张 map 复制到另一张 map 中?