【问题标题】:How to use std::optional in C++如何在 C++ 中使用 std::optional
【发布时间】:2017-02-21 12:39:59
【问题描述】:

在 C++17 中引入了std::optional,我对这个决定感到高兴,直到我查看了ref。我知道 Optional/Maybe 来自 Scala、Haskell 和 Java 8,其中 optional 是一个单子并遵循单子定律。在 C++17 实现中情况并非如此。我应该如何使用std::optional,没有像mapflatMap/bind这样的函数,使用std::optional与例如从函数返回-1nullptr有什么优势?它无法计算结果? 对我来说更重要的是,为什么 std::optional 不被设计成一个单子,有什么原因吗?

【问题讨论】:

  • C++ 不是 Haskell。
  • 如果 -1 已经是一个有效的返回值怎么办?
  • 如果您返回 int 并返回 -1 作为失败,这意味着 -1 冷永远不会是输入的有效输出。大多数时候你不能这样做。至于使用情况,你应该咨询reference
  • 你不能从返回类型为int的函数返回nullptr
  • "但可选类型显然来自函数式编程" 这可能是你困惑的根源。

标签: c++ functional-programming monads c++17


【解决方案1】:

P0798r0 提议与此,以及相关的实现here on Github。该提案还参考了通用单子接口提案,以及类似可用的 std::expected。也可以使用这些实现。

【讨论】:

    【解决方案2】:

    如果没有像 map 和 flatMap/bind 这样的函数,我应该如何使用 std::optional

    Haskell 中的Maybe 在没有fmap 的情况下完全可用,它代表一个可能存在也可能不存在的值。它还为类型系统带来了区别,因此您需要处理这两种情况。

    如果计算结果失败,使用 std::optional 与返回 -1 或从函数返回 nullptr 相比有何优势?

    你怎么知道错误情况是什么?是0-1MAX_INTnullptr 还是别的什么?如果我同时拥有unsigned intint 返回值以及之前返回的int 版本-1,您应该将它们都更改为MAX_INT 还是让它们返回不同的值? std::optional 避免了这个问题。

    对我来说更重要的是,为什么 std::optional 没有设计成 monad,有什么原因吗?

    C++ 目前有单子吗?在与容器不同的抽象之前,没有真正的方法来添加该功能。

    【讨论】:

    • 我会说 C++ 中确实有单子(例如 optional 和 vector)。它缺少的是对它们进行 monadic 操作的好语法,但将它们视为 monad 仍然很有用。
    • @toth 操作(以及它们遵守单子定律的事实)肯定是单子的重要部分,而不是类型?没有操作, optional 只是一个类型。
    【解决方案3】:

    可以std::optional 上定义bindreturn,所以在这个意义上它仍然是一个Monad。

    例如,一个可能的bind

    template<typename T1, typename T2>
    std::optional<T2> bind(std::optional<T1> a, std::function< std::optional<T2>(T1)> f) {
       if(a.has_value()) return f(a.value());
       return std::optional<T2>{};
     }
    

    定义它实际上可能很有用。

    至于为什么标准库不附带这个或类似的东西,我认为答案是语言中的首选风格之一。

    【讨论】:

    • 这行不通。你想要的东西类似于template&lt;typename T1, typename F&gt; auto bind(std::optional&lt;T1&gt; a, F f) -&gt; std::optional&lt;std::decay_t&lt;decltype(f(*a))&gt;&gt;;
    • @T.C.,确实在我的版本中,编译器无法推断 T2,因此您必须在调用 bind 时指定它,但我想说这仍然算作工作。我同意您的版本比实际上更好,因为它可以进行类型推断并且更有效(如果您不想使用,则无需使用 std::function ),但至少对我来说,很难说出 @ 的类型987654327@应该是从看声明。
    • @T.C.,我也相信您不希望在您的尾随返回类型上使用 std::optional。绑定中的f 应返回std::optional,您的类型签名将是fmap 的正确签名。
    • 第二点很好。那是打错字了。 (如果您想要明确指定的参数,至少交换您的模板参数顺序并将第二个函数参数的类型包装在非推导上下文中,以便仍然可以推导 T1。)
    猜你喜欢
    • 2017-10-28
    • 2022-06-10
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 2021-11-29
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多