如何在<T>没有 if 语句的情况下返回可选?

How to return an optional<T> without an if statement?

本文关键字:返回 情况下 语句 没有 lt gt if      更新时间:2023-10-16

假设我有一个函数,它查找并返回向量的最小元素。如果向量为空,则应返回一个空的可选对象。有没有办法让我使用 optional<T> 构造函数来避免使用 if 语句或三元运算符?

使用 if 语句:

optional<Foo> GetMinElement(vector<Foo> foos) {
  vector<Foo>::iterator min_foo = std::min_element(foos.begin(), foos.end());
  bool found_min_element = (min_foo != foos.end());
  if (found_min_element) {
    return *min_foo;
  } else {
    return nullopt;
  }
}

使用三元运算符:

optional<Foo> GetMinElement(vector<Foo> foos) {
  vector<Foo>::iterator min_foo = std::min_element(foos.begin(), foos.end());
  bool found_min_element = (min_foo != foos.end());
  return found_min_element ? optional<Foo>(*min_foo) : optional<Foo>(nullopt);
}

天真地,我只是希望能够将stl算法的输出传递给optional<T>构造函数,并让它处理检查空指针的逻辑。这有什么成语吗?

您必须记住,结束迭代器不是空指针。 如果范围是子范围,它甚至可以是有效的迭代器。

我编写自己的范围算法。 它们遵循与您的模式不同的模式。

范围算法采用class Range,执行启用 adl 的 begin/end并运行迭代器算法。 然后它返回一个可选的迭代器(如果end为空)。

这与您的略有不同,因为我不会返回元素的副本。

它们可以在原件所在的任何地方使用(添加make_range(start,finish))。


如果您不喜欢 if 和 ? 的语法,这些可能会有所帮助:

template<class T>
std::optional<std::decay_t<T>> maybe(bool engage, T&&t){
  if (!engage) return {};
  return std::forward<T>(t);
}

甚至:

templace<class F>
std::optional<std::decay_t<std::result_of_t<F()>>>
perhaps(bool do_it, F&&f){
  if (!engage) return {};
  return std::forward<F>(f)();
}

?一样短路。

namespace adl_helper{
  using std::begin; using std::end;
  template<class R> auto adl_begin(R&&)->decltype(begin(std::declval<R>())){
    return begin(std::forward<R>(r));
  }
  template<class R> auto adl_end(R&&)->decltype(end(std::declval<R>())){
    return end(std::forward<R>(r));
  }
}
using adl_helper::adl_begin;
using adl_helper::adl_end;
template<class R>using iterator_t=decltype(adl_begin(std::declval<R>()));
template<class R>
optional<iterator_t<R>> min_element(R&& r) {
  auto ret = std::min_element(adl_begin(r), adl_end(r));
  return maybe(ret!=adl_end(r), ret);
}

我发现它比你的版本更有用。

您有时确实需要做额外的*,或使用助手。

optional 似乎没有一个构造函数,该构造函数有时会产生一个空的可选函数,而sumetimes会产生一个完整的可选函数。

也许你可以做一个帮手:

template<typename Iter>
optional<typename Iter::value_type> try_deref(Iter pos, Iter singular)
{
    if ( pos != singular )
        return *pos;
    return {};
}

示例用法:

optional<Foo> GetMinElement(std::vector<Foo> const &foos)
{
    auto min_foo = std::min_element(foos.begin(), foos.end());
    return try_deref(min_foo, foos.end()); 
}