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
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";
}