std::ranges::find vs std::find

std::ranges::find vs std::find


8

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

0

1 Answer
1


11

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

6

  • 1

    What is the motivation for equality_comparable_with to require the existence of a common reference? What does it have to do with comparison?

    – Evg

    11 hours ago


  • 1

  • Thanks. Unfortunately, the answer there doesn't really explain the motivation, "the design says", that's all. I guess I need to study the document that answer refers to.

    – Evg

    10 hours ago

  • 3

    @Evg Well, what does it even mean to say that an S (a type with two ints in it) is "equal" to an int? There are certain properties that we think about when we think about equality… so S{1, 2} == 1 and S{1, 3} == 1, does that imply that S{1, 2} == S{1, 3}? But S isn't even comparable to itself, so what can we even meaningfully say about this? This example strikes me more like it's using == for the syntactic convenience of find more than anything else.

    – Barry

    10 hours ago

  • @Evg: motivation of constraints are to have meaningful contraints, i.e just have operator< (for ordering) is "strange" (so no operator >) (even if it is indeed the "old" C++ way).

    – Jarod42

    10 hours ago



Leave a Reply

Your email address will not be published. Required fields are marked *