Читая cppreference.com, я заметил ranges::find_last_if не возвращает итератор, а ranges::find_if возвращает. Мне интересно, есть ли веская причина для такого решения?
Судя по всему, правильно использовать ranges::find_if с обратным диапазоном:
const auto it = std::ranges::find_if (data | std::views::reverse, func);
Тем не менее, ranges::find_last_if возврат итератора кажется мне более интуитивным, поэтому мне интересно узнать о его цели.
Кстати, правильное использование: const auto it = std::ranges::find_last_if (data, func).begin();





По сути, алгоритмы std::ranges возвращают конечный итератор всякий раз, когда могут.
Например,
std::ranges::for_each возвращает in_fun_result. Компонент in — это итератор конца исходного диапазона.std::ranges::copy возвращает in_out_result. in — итератор конца исходного диапазона, а out — итератор конца целевого диапазона. (std::copy возвращает только конец диапазона назначения.)std::ranges::fill и std::ranges::generate возвращают итератор в конец диапазона назначения. (Алгоритмы std ничего не возвращают.)Причина в том, что, в отличие от традиционных алгоритмов std, ranges используют итератор и страж. Единственное, что вы можете сделать со стражей (которая сама по себе не является итератором), — это сравнить ее с итератором. Если они сравниваются равными, это означает, что достигнут конец диапазона.
Поскольку дозорный объект менее полезен, чем итератор, и этим алгоритмам в любом случае необходимо получить конечный итератор, они возвращают этот итератор, чтобы не потерять ценную информацию.
Для std::ranges::find_last_if это означает, что он должен вернуть итератор найденному элементу и конечный итератор. Они естественным образом образуют subrange, и именно это std::ranges::find_last_if на самом деле и возвращает.
Если вам не нужен конечный итератор, вы можете извлечь первый итератор, используя subrange::begin.
const auto it = std::ranges::find_last_if (data, func).begin();
Обоснование можно найти здесь.