C++23的Optional::transform和Optional::and_then有什么区别?

问题描述 投票:0回答:3

C++23 添加了一些关于可选值的“一元式”功能,作为

optional<T>
:

的方法

optional<T>::and_then()
(忽略
this
的限定词):

template<class F> constexpr auto and_then(F&& f); 

退货 对包含的值调用 f 的结果(如果存在)。 否则,返回返回类型的空值。

optional<T>::transform()
(忽略
this
的限定词):

template<class F> constexpr auto transform(F&& f);

如果

std::optional
包含值,则返回
f
,其中包含对所包含值调用
*this
的结果。否则,返回此类类型的空
std::optional

那么,这两个函数不是做同样的事情吗?

c++ monads monad-transformers stdoptional c++23
3个回答
20
投票

假设您有一个

optional<T1>
值。

  • transform()
    可让您将选项传递给
    T2 foo(T1 x)
    ;
  • 等函数
  • and_then()
    可让您将选项传递给
    optional<T2> bar(T1 x)
    ;
  • 等函数

...最后得到一个

optional<T2>
。因此,
transform()
会将函数的输出“重新装箱”为可选值,而
and_then()
将期望函数自行返回装箱值。

您可能还会认为

transform
就像
std::transform
:您将一个函数应用于“每个元素”;在容器中,它可以是任意数量的元素,在可选元素中,它可以是 0 或 1 个元素。

另请参阅这个问题


1
投票

and_then
仅接受
T -> std::optional<U>
类型的函数(而
transform
可以自由接受返回任何类型的函数)。

如果您只是

transform
使用这样的功能,您将得到一个
std::optional<std::optional<U>>

and_then
然后将
std::optional<std::optional<U>>
压平成
std::optional<U>

这就是所有单子:

transform
由类型级别
flatten
组成。想想
range<range<U>>
future<future<U>>


0
投票

and_then
是单子
bind
又名
flatmap
又名
>>=
transform
是函子
map

一般可以用

map
来表达
bind
,但反之则不然,因为函子不一定是单子。当然,
std::optional
的特定 monad 可以随时打开,因此这两个函数都可以用普通的 C++23 之前的
std::optional
API 来表达。因此,为什么 C++ 标准定义这两个函数的问题并不比为什么它定义这两个函数的问题更好。也许标准希望为程序员提供一个独立的标准函数接口和标准单子接口。这两个界面本身都是有用且重要的。

© www.soinside.com 2019 - 2024. All rights reserved.