Search code examples
c++c++20std-ranges

Why doesn't std::ranges::find compile while std::find works fine?


Consider this code:

#include <vector>
#include <iostream>
#include <cstdint>
#include <ranges>

int main()
{
    struct S {
        int  a;
        int  b;
        bool operator==(int other) const { return a == other; }
    };
    std::vector<S> iv{
        {1, 2},
        {3, 4}
    };

    // this works
    if (auto const it{std::find(iv.begin(), iv.end(), 1)}; it != iv.end()) {
        std::cout << "Found!\n" << "\n";
    }

    //std::ranges::find(iv, 2); // <-- why does this not compile
    
}

My impression was that the call convention of ranges would be a 1-to-1 mapping of the corresponding original algorithm (i.e., just skip the .begin() and .end(), and it should work as before).

Clearly this is not the case here. What am I missing?

A link to the code: https://godbolt.org/z/3a6z9c5of


Solution

  • ranges::find uses ranges::equal_to by default to compare the elements of the range with the value, and the call operator of ranges::equal_to constrains the two types to satisfy equality_comparable_with, which is S and int in your example.

    equal_comparable_with requires S to be comparable with itself and needs to have a common reference with const int&, which is not your case.

    The simple workaround is to use the projection function to project S to S::a

    if (auto const it{std::ranges::find(iv, 1, &S::a)}; it != iv.end()) {
        std::cout << "Found!\n" << "\n";
    }