I've been using extensively boost::algorithm::find_if_backward
to get a forward iterator to the last element in a range satisfying a predicate.
How do I accomplish the same task using Range-v3?
This is my attempt, which looks a bit clunky; and I'm not even sure is robust enough. Actually, as suggested in a comment, the code is not robust enough, because when no element is found, range_it_to_last_2
ends up being std::next(v.begin(), -1)
, which is undefined behavior, I believe.
#include <algorithm>
#include <boost/algorithm/find_backward.hpp>
#include <boost/hana/functional/partial.hpp>
#include <iostream>
#include <range/v3/algorithm/find_if.hpp>
#include <range/v3/view/reverse.hpp>
using boost::algorithm::find_if_backward;
using ranges::find_if;
using ranges::views::reverse;
auto constexpr is_2 = boost::hana::partial(std::equal_to<>{}, 2);
int main() {
std::vector<int> v{0,1,2,2,2,3};
// What I have been doing so far:
auto boost_it_to_last_2 = find_if_backward(v, is_2);
// The Range-v3 analogous I could come up with, but it's ugly:
auto range_it_to_last_2 = std::next(find_if(v | reverse, is_2).base(), -1);
for (auto it = v.begin(); it <= boost_it_to_last_2; ++it) {
std::cout << *it << ' ';
} // prints 0 1 2 2 2
std::cout << std::endl;
for (auto it = v.begin(); it <= range_it_to_last_2; ++it) {
std::cout << *it << ' ';
} // prints 0 1 2 2 2
std::cout << std::endl;
}
Assuming you always know that a match is found, why not simplify to the following, getting the identical output:
#include <algorithm>
#include <boost/algorithm/find_backward.hpp>
#include <boost/hana/functional/partial.hpp>
#include <fmt/ranges.h>
#include <range/v3/algorithm/find_if.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/reverse.hpp>
using boost::algorithm::find_if_backward;
using ranges::find_if;
using ranges::views::reverse;
using ranges::subrange;
auto constexpr pred = boost::hana::partial(std::equal_to<>{}, 2);
int main() {
std::vector<int> v {0,1,2,2,2,3};
auto boost_match = find_if_backward(v, pred);
auto range_match = find_if(v | reverse, pred).base();
static_assert(std::is_same_v<decltype(boost_match), decltype(range_match)>);
fmt::print("boost: {}\nrange: {}\n",
subrange(v.begin(), boost_match+1),
subrange(v.begin(), range_match));
}
Prints
boost: {0, 1, 2, 2, 2}
range: {0, 1, 2, 2, 2}
(Some toy respellings for fun: https://godbolt.org/z/ccPKeo)