So I recently had a question about using the ranges variant of the std::ranges::find algorithm and the answer used a projection:
if (auto const it{std::ranges::find(iv, 1, &S::a)}; it != iv.end()) {
std::cout << "Found!\n" << "\n";
}
Specifically the &S::a part.
Normally I have seen a lambda being used in this place, but here we use a pointer to a class member. Is this transformed into a lambda or is there some overload selection going on?
Can someone break down how this, seemingly magic, works?
&S::a is a pointer to the data member of class S. Just like pointers to member functions, they both can be invoked through specific class objects, so they are callables.
In c++20, constraint functions (which are under namespace ranges) in <algorithm> and range adaptors in <ranges> (or most of the standard library) uniformly invoke callables through std::invoke.
std::invoke is a generalized interface for calling callables. In addition to calling ordinary functions with the common form of f(x), it can also handle pointers to data members/functions.
Let's go back to your example. Basically, ranges::find determines whether the current element is equal to the value via the condition if (std::invoke(proj, *it) == value), where proj is &S::a and *it returns an object of type S.
So std::invoke(&S::a, obj_s) returns a reference to the member a of the obj_s, which is a reference to an int.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With