Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

std::views:filter for some reason can't deduce argument type in a function pointer

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>)’

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading