迭代 std::Optional

yai*_*chu 3 c++ option-type stdoptional

我尝试迭代std::optional:

for (auto x : optionalValue)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

预期如果为optionalValue空则不执行任何操作,但如果其中有值则执行一次迭代,就像它在 Haskell 中一样(可以说这很std::optional流行):

forM optionalValue
( \x ->
    ...
)
Run Code Online (Sandbox Code Playgroud)

为什么我不能迭代可选的?还有另一种更标准的 C++ 方法可以做到这一点吗?

bit*_*ask 8

std::optional没有begin()andend()对。所以你不能基于范围来超过它。相反,只需使用if条件即可。

请参阅替代方案 2,了解最接近您想要做的事情。

编辑:如果您有临时的调用结果,则不必明确检查它:

if (auto const opt = function_call()) {
  do_smth(*opt);
}
Run Code Online (Sandbox Code Playgroud)

的检查static_cast<bool>(opt)是由 隐式完成的if。


替代方案1

另一种选择是不使用std::optional<T>but std::variant<std::monostate, T>。然后,您可以使用overloaded惯用法或创建自定义类型来处理单态:

template <typename F>
struct MaybeDo {
  F f;

  void operator()(std::monostate) const {}
  template <typename T>
  void operator()(T const& t) const { f(t); }
};
Run Code Online (Sandbox Code Playgroud)

这将允许您使用某些函数访问该值:

std::variant<std::monostate, int> const opt = 7;
std::visit(MaybeDo{[](int i) { std::cout << i << "\n"; }}, opt);
Run Code Online (Sandbox Code Playgroud)

替代方案2

您还可以将可选内容包装在允许您对其进行迭代的事物中。主意:

template <typename T>
struct IterateOpt {
  std::optional<T> const& opt;
  
  struct It {
    std::optional<T> const* p;
    It& operator++() {
      p = nullptr;
      return *this;
    }
    It operator++(int) {
      return It{nullptr};
    }
    auto const& operator*() const { **p; }
  };
  auto begin() const {
    if (opt) return It{&opt};
    else end();
  }
  auto end() const {
    return It{nullptr};
  }
};
Run Code Online (Sandbox Code Playgroud)

这是如何执行此操作的粗略草图,可能需要一些热爱才能处理不同的情况(例如非常量可选)。

您可以使用它来“迭代”可选的:

for (auto const& v: IterateOpt{function_call()}) {
  do_smth(v);
)
Run Code Online (Sandbox Code Playgroud)