【问题标题】:Generically return a optional<T> / nullopt一般返回一个可选的<T> / nullopt
【发布时间】:2022-01-18 20:36:18
【问题描述】:

我正在尝试实现一个通用的 find_if_opt 方法,它实际上与 std::ranges::find_if 相同(但是它返回一个 Optional)

到目前为止,这是我的实现。

    template <typename X, typename Z>
    inline auto find_if_opt(const X& ds, const Z& fn) {
        const auto it = ranges::find_if(ds, fn);
        if (it != end(ds)) {
            return std::make_optional(*it);
        }
        return {};
    }

    auto test() {
        std::vector v{1,2,3,4,5};
        return ranges::find_if_opt(v, [](auto i){
            return i == 2;
        });
    }

这是一个更大的 std::ranges 的一部分,比如 c++17 算法的包装器。请参阅https://godbolt.org/z/3fEe8bbh9(有关整个相关标头)

使用{}时编译器错误为:

<source>:29:16: error: cannot deduce return type from initializer list
        return {};
               ^~

我也尝试过使用 std::nullopt,导致:

<source>:41:6:   required from here
<source>:30:21: error: inconsistent deduction for auto return type: 'std::optional<int>' and then 'std::nullopt_t'
         return std::nullopt;
                     ^~~~~~~

PS:如果您对我的范围::包装器有任何建议,而我仍然坚持使用 c++17,请随时提出。

【问题讨论】:

  • nullopt 不是std::optional,它是一种可用于默认构造std::optional 的类型。返回std::optional&lt;X&gt;{};
  • 使用std::optional&lt;X&gt;{};不起作用,因为X是数据结构的类型,即X是std::vector&lt;int&gt;

标签: c++ templates c++17 std


【解决方案1】:

您可以使用ranges::range_value_t 获取value_typeX

template <typename X, typename Z>
inline std::optional<std::ranges::range_value_t<X>> 
find_if_opt(const X& ds, const Z& fn) {
    const auto it = std::ranges::find_if(ds, fn);
    if (it != end(ds)) {
        return *it;
    }
    return {};
}

或者使用std::iter_value_t获取迭代器的value_type

template <typename X, typename Z>
inline auto
find_if_opt(const X& ds, const Z& fn) {
    const auto it = std::ranges::find_if(ds, fn);
    if (it != end(ds)) {
        return std::make_optional(*it);
    }
    return std::optional<std::iter_value_t<decltype(it)>>{};
}

或 C++20 之前的版本

template <typename X, typename Z>
inline auto find_if_opt(const X& ds, const Z& fn) {
  const auto it = ranges::find_if(ds, fn);
  if (it != end(ds)) {
    return std::make_optional(*it);
  }
  return std::optional<std::decay_t<decltype(*it)>>{};
}

【讨论】:

  • 有没有 c++17 的方法可以做到相当于std::ranges::range_value_t?我仍在使用 c++17,这是 wrapper 等范围的一部分(请参阅 Godbolt 链接)
  • @Mr.Pasta:仅供参考:如果您不能使用 C++20 解决方案,则不应使用 c++20 标记您的问题。
  • 好点。谢谢!我的想法是该项目必须同时使用 c++17 和 c++20 构建,所以我认为使用两者进行标记是有意义的。
  • @mr.pasta 我可能会编写一个辅助函数,它接受一个可取消引用并对其进行测试,并返回一个可选的。叫它maybe_optionalreturn maybe_optional(it!=end(ds),it);
猜你喜欢
  • 2012-07-11
  • 1970-01-01
  • 1970-01-01
  • 2016-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-22
  • 2013-05-30
相关资源
最近更新 更多