基于范围的 for 循环表达式中的临时可选

Dmi*_*eev 7 c++ std boost-optional c++17

假设我们有一个返回 的函数std::optional<A>。那么在基于范围的 for 循环中使用结果的正确方法是什么?最简单的方法不起作用:

for (auto&& e : a().value()) {
                   // ^--- A&& is returned, so A is destructed
                   // before loop starts
Run Code Online (Sandbox Code Playgroud)

T optional::value() &&如果我们用代替 ,这个问题就不会存在T&& optional::value() &&,但 STL 和 Boost 都以第二种方式定义它。

处理这种情况的正确方法是什么?我不喜欢我能想到的两种解决方案(沙箱):

std::experimental::optional<A> a() {
  // ...
}

void ok1() {
  // ugly if type of A is huge
  for (auto&& e : A(a().value())) {
     // ...
  }
}

void ok2() {
  // extra variable is not used
  // if for some reason we are sure that we have a value
  // and we skip checks
  auto&& b = a();
  for (auto&& e : b.value()) {
    // ...
  }
}

// it may be that the best choice is to define
A aForced() {
    return A(a().value());
}
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 2

这解决了你的问题:

template<class T>
std::decay_t<T> copy_of(T&& t){
  return std::forward<T>(t);
}

template<class T, std::size_t N>
void copy_of(T(&)[N])=delete;
Run Code Online (Sandbox Code Playgroud)

然后:

for(auto&& x:copy_of(a().value()))
Run Code Online (Sandbox Code Playgroud)

copy_of技术通常解决在循环中使用返回右值引用的函数for(:)


另一种方法是value_or_run(T&&, F&&f)采用 lambda 的编写方式也很有用。在F你可以做任何你想做的事情,比如抛出,它返回一个而T不是一个T&&

相似地,value_or

我个人optional使用的 emplace 语法是value_or-- 如果您使用的语法是这样的,那么.value_or( throw_if_empty{} ), where throw_if_emptyhas anoperator T()会抛出可选的空错误。