I was learning how to use std::ranges and decided to experiment with c++23 std::views::enumerate and wrote something like this:
using namespace std;
auto isnt_nullptr(auto t) {
return get<1>(t) != nullptr;
}
int main() {
int i1 = 1, i2 = 3, i4 = 8;
int* ptrs[5]{nullptr, &i1, &i2, nullptr, &i4};
for (auto [index, ptr] : ptrs | views::enumerate
| views::filter(isnt_nullptr)) {
puts(format("{}: {}", index, *ptr).c_str());
}
return 0;
}
and it spat out usual error gibberish
error: no match for call to '(const std::ranges::views::_Filter) (<unresolved overloaded function type>)'
By the way I was doing this in a compiler explorer using gcc (trunk) with -std=c++23 flag, no other flags were applied
I thought that maybe for some reason compiler couldn't deduce function argument so I explicitly wrote: auto isnt_nullptr(tuple<long int, int*> t)
and it worked. I thought that it is too bothersome to specify a type every time and tried using lambda instead without much hope.
So I used this instead of a function pointer:
for (auto [index, ptr] : ptrs | views::enumerate
| views::filter([](auto pair){
return get<1>(pair) != nullptr;
})
) {
puts(format("{}: {}", index, *ptr).c_str());
}
and it worked, after that I wrapped my function, which accepted auto as an argument, in the lambda:
[](auto t){ return isnt_nullptr(t); }
and it worked as well and I have no clue why.
Can someone please explain why function pointer is a no-no in this case?
isnt_nullptr
is not a function. It is a function template. Therefore you can't have a function pointer to it, only to one of its specializations.
When passing isnt_nullptr
to views::filter
, views::filter
takes its argument as a generic type, so there is no target type that could be used to deduce which specialization of isnt_nullptr
you want to pass. Therefore the error mentioning that the overload set for isnt_nullptr
couldn't be resolved to a single function.
You can state explicitly which specialization you want to pass with views::filter(isnt_nullptr<tuple<long int, int*>>)
or you can use the lambda approach you showed.
The lambda approach works because you are not passing a function at all in that case. You are instead passing the lambda object, which has its operator()
called inside views::filter
. Overload resolution to a specific specialization of the templated operator()
will happen at that call site.