Home > database >  Generically return a optional<T> / nullopt
Generically return a optional<T> / nullopt

Time:12-16

I am trying to implement a generic find_if_opt method which is virtually identical to std::ranges::find_if (however it return an Optional)

So far this is my implementation.

    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;
        });
    }

This is a part of a larger std::ranges like wrapper around c 17 algorithms. See https://godbolt.org/z/3fEe8bbh9 (for entire relevant header)

When using {} the compiler error is:

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

I have also tried using std::nullopt, which causes:

<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: if you have suggestions regarding my ranges:: wrapper while I'm still stuck on c 17, feel free to.

CodePudding user response:

You can use ranges::range_value_t to get value_type of X

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 {};
}

Or using std::iter_value_t to get value_type of iterator

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)>>{};
}

Or pre-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)>>{};
}
  • Related