为什么我们需要使用std::nullopt?

10

我们什么时候可以使用统一初始化来轻松地默认构造std::optional<T>

std::optional<T> foo() {
   if (on_error)
      return {};

    // ...
}

std::nullopt 解决了上述情况存在的任何缺陷吗?


1
nullptr、{}和nullopt之间的区别 - underscore_d
2个回答

18

编号。

这是一种完全有效的默认构造optional的方式。

即使是赋值,您也可以使用= {}而不是使用std::nullopt来复制赋值一个默认构造的optional:

cppreference实际上已经说明了这一点:

nullopt_t的构造函数的约束存在是为了支持将可选对象解除关联的语法,包括op = {};op = nullopt;

… 原始的特性提案也说明了这一点:

请注意,这不是将可选对象解除关联的唯一方法。 您还可以使用:

op = std::nullopt;
你可能会问为什么需要存在 std::nullopt。提案也解释了这个问题

它在接口中引入了冗余

[类似的例子]

另一方面,有些场景下,无法用其他便捷的符号替换 nullopt 的使用:

void run(complex<double> v);
void run(optional<string> v);

run(nullopt);              // pick the second overload
run({});                   // ambiguous

if (opt1 == nullopt) ...   // fine
if (opt2 == {}) ...        // illegal

bool is_engaged( optional<int> o)
{
  return bool(o);          // ok, but unclear
  return o != nullopt;     // familiar
}

虽然某些情况下使用{}语法是可以的,但使用nullopt会使程序员的意图更加清晰。请比较以下两种写法:

optional<vector<int>> get1() {
  return {};
}

optional<vector<int>> get2() {
  return nullopt;
}

optional<vector<int>> get3() {
  return optional<vector<int>>{};
}
简而言之,std::nullopt 可能很有用,但在你的情况下,它只是风格问题。

4
以上方法有缺点吗,std::nullopt可以解决这个问题吗?
是的。
在某些情况下,您可能希望有条件地返回未联接的可选对象(即空),而{}初始化语法不能非歧义地用于推断std::nullopt_t类型。例如,在通过三元运算符表达式返回空或非空可选值时,如Return Optional value with ?: operator所述。
return it != map.end() ? std::make_optional(it->second) : std::nullopt;

我理解的是,这仅适用于函数的返回类型声明为 auto 的情况,对吗? - Sebastian Hoffmann
1
@SebastianHoffmann 不需要函数,甚至都不需要:https://wandbox.org/permlink/ICRS7wfj801CgGIf - Thomas Sablik
1
关联的问题是关于另一种情况的。您的 true 表达式与返回类型匹配,但是,在那里 {} 不是一个有效的表达式。 (链接:https://coliru.stacked-crooked.com/a/222ee7027638ba2c) - Asteroids With Wings
这解决了问题,谢谢。 - Sebastian Hoffmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接