Vincent
Vincent

Reputation: 60381

Pointer to function and std::function : the first one compiles and not the second one?

I'm not familiar with pointer to functions and I'm currently making some tests. But in the following program, I don't understand why the first version works and why the second version does not compile. What would be the correct syntax ?

#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional>

template<typename Type> 
void display(const std::vector<Type>& v)
{
    if (!v.empty()) {
        for (unsigned int i = 0; i < v.size()-1; ++i)
            std::cout<<v[i]<<" ";
        std::cout<<v[v.size()-1];
    }
}

// Compiles 
template<typename Type> 
void apply1(std::vector<Type>& v, void(f)(Type*, Type*, Type))
{
    f(&*v.begin(), &*v.end(), 0);
}

// Does not compile
template<typename Type> 
void apply2(std::vector<Type>& v, std::function<void(Type*, Type*, Type)> f)
{
    f(&*v.begin(), &*v.end(), 0);
}

int main()
{
    std::vector<double> v = {1., 2., 3., 4., 5., 6.};
    display(v); std::cout<<std::endl;
    apply1(v, std::iota);
    display(v); std::cout<<std::endl;
    apply2(v, std::iota);
    display(v); std::cout<<std::endl;
    return 0;
}

The error is the following :

error: cannot resolve overloaded function 'iota' based on conversion to type 'std::function<void(double*, double*, double)>'

Upvotes: 1

Views: 191

Answers (1)

Xeo
Xeo

Reputation: 131799

A function pointer provides what I call a conversion context. It explicitly states which of the overloads is meant, whilst std::function does not. The constructor of std::function takes in any callable entity and as such provides no context to disambiguate which overload is meant. See also this question.

To manually disambiguate, either cast the function pointer

apply2(v, static_cast<void(*)(double*,double*,double)>(std::iota));

or use a named function pointer

void (*iota)(double*, double*, double) = std::iota;
apply2(v, iota);

or use a lambda

apply2(v, [](double* f, double* l, double d){ std::iota(f, l, d); });

Upvotes: 3

Related Questions