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

Why C++ function can't be used as a type?

What is the reason C++ function can’t be used as a type to be passed as a functor or predicate?

One of the main purposes of the functor is to behave as a function so that it could be called in a function manner. Well, it could do more (have states, etc.), but why we can’t use functions instead of functors it the sole purpose of the functor is to be called?

Well, the object should be constructed, as well for the functors, but this could be skipped if we see that the function was passed.

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

In the code below both function and functor behave similarly until I try to pass them to std::map.

#include <algorithm>
#include <map>
#include <ranges>
#include <span>
#include <vector>

bool std_span_less(const std::span<const unsigned int> lhs, const std::span<const unsigned int> rhs) {
    return std::ranges::lexicographical_compare(lhs, rhs);
}

struct std_span_less_fn {
    bool operator() (const std::span<const unsigned int> lhs, const std::span<const unsigned int> rhs) const {
        return std::ranges::lexicographical_compare(lhs, rhs);
    }
};

int main()
{
    using fn_type = bool (*)(const std::span<const unsigned int> , const std::span<const unsigned int> );

    std::vector<unsigned int> lexems = { 0, 1, 2 };

    std_span_less_fn fn_obj;
    auto span1 = std::span(&(lexems[0]), 1);
    auto span2 = std::span(&(lexems[0]), 2);

    auto res_fn = fn_obj(span1, span2); // Can be used as function
    auto res = std_span_less(span1, span2);  // Naturally used as function

    std::map<std::span<const unsigned int>, int, std_span_less_fn> sentences_fn;
    std::map<std::span<const unsigned int>, int, std_span_less> sentences; // Doesn't compile

    sentences_fn[std::span(&(lexems[0]), 1)] = 0;
    sentences_fn[std::span(&(lexems[2]), 1)] = 2;
    sentences_fn[std::span(&(lexems[1]), 1)] = 1;
}

Is the only reason to restrict passing functions is this object construction or I am missing something else?

I read the documentation on the std::map but failed to find explicit statement what makes impossible to pass a function as Compare except my vague "Is function a type?" thoughts.

>Solution :

You can pass functions as a template paramter, but you need to pass it as a pointer to the function. The reason you need this is because a function type is exactly that, only a type, you can’t create an object from it like you can with functor. What you can do is have a pointer to a function and you can assign to that pointer what actual function it should point to. Doing that changes

std::map<std::span<const unsigned int>, int, std_span_less> sentences;

to

std::map<std::span<const unsigned int>, int, decltype(std_span_less)*> sentences{&std_span_less};
                                             ^ make a pointer type  ^            ^^^^^^^^^^^^^^
                                                                                 |            
                        initialize with a pointer to the function you want to use

You can alternatively use

std::integral_constant<decltype(&std_span_less), std_span_less>

as the compare type which wraps the function pointer value into the type so you do not need to initialize the map with the pointer. That changes the code to be:

std::map<std::span<const unsigned int>, int,
         std::integral_constant<decltype(&std_span_less), std_span_less>> sentences;
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