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