std::optional<T> 和对 T 进行非常量引用的函数

std::optional<T> and functions taking a non-const reference to T

假设我有一个函数

void set_value(MyType& x);

我想用类型为

的变量来调用它
std::experimental::optional<MyType> myvar

我不能简单地调用 set_value(*myvar),因为 myvar 可能没有值。在所有情况下,如何安全地确保 set_value()myvar 上的结果?

我想避免写:

decltype(my_var)::value_type tmp;
set_value(tmp);
my_var = tmp;

你可以这样做:

if (!my_var) { my_var.emplace(); }
set_value(*my_var);

但更好的方法是简单地将 set_value 的签名更改为:

MyType set_value();

这样你就可以写:

my_var = set_value();

Input/Output 参数糟透了。

template<class F, class T>
decltype(auto) set_optional( F&& f, std::experimental::optional<T>& o ) {
  if (!o) o.emplace();
  return std::forward<F>(f)(*o);
}

现在您可以:

set_optional( set_value, myvar );

而且有效。

但是请注意,引用 MyType 的函数需要输入和输出参数。返回仅输出参数。许多人将其重用于仅输出参数。这会导致像您 运行 上面那样的问题,以及不必要的默认构造。

set_value(*myvar);

您可以内联执行此操作:

if (!myvar) myvar.emplace();
set_value(*myvar);

如果为空,我们构造它,然后使用它。

或者,不同的重构(我认为这很好):

template<class T, class...Args>
T& emplace_or( std::experimental::optional<T>& o, Args&&...args ) {
  if (!o) o.emplace(std::forward<Args>(args)...);
  return *o;
}

然后:

set_value(emplace_or(myvar));

或者最后一个选项:

set_value(void(!myvar?myvar.emplace(),void(),3:16),*myvar)

void(),3:16: 对于如此喜爱的可选 "hello world" 他们给了它唯一的内容,任何相信它的人都不会出现段错误,但有一个正确的程序。