Search code examples
c++algorithmstdvectorstd-rangesc++23

ranges::max on filter_view returns a removed element


This question is summarized best by a code example

int foo() {
    const std::vector<int> elems{4, 5, 6, 2, 1, 9, 8};
    const auto is_even = [](int e) { return e % 2 == 0; };
    const auto cmp = [](int x, int y) { return x < y; };

    auto evens = elems | std::views::filter(is_even);  // 4 6 2 8
    return std::ranges::max(elems, cmp);  // 9 ????
}

Somehow despite running max on the filter_view it is returning an element that should have been filtered out.

godbolt


Solution

  • ... despite running max on the filter_view ...

    You are not running max on the filter_view. You are running max on the vector<int> elems.

    elems is unaffected by your view - and it would be especially strange if it wasn't unaffected since elems is const.

    You need to apply max to evens which is your filter_view.

    return std::ranges::max(evens, cmp);
    

    ... or, since the built in comparator for max will do the right thing:

    int foo() {
        const std::vector<int> elems{4, 5, 6, 2, 1, 9, 8};
        const auto is_even = [](int e) { return e % 2 == 0; };
    
        auto evens = elems
                   | std::views::filter(is_even);
    
        return std::ranges::max(evens); // no cmp needed
    }