Я не знаком с указателем на функции, и в настоящее время я делаю некоторые тесты. Но в следующей программе я не понимаю, почему первая версия работает и почему вторая версия не компилируется. Какой будет правильный синтаксис?
#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;
}
Ошибка заключается в следующем:
error: cannot resolve overloaded function 'iota' based on conversion to type 'std::function<void(double*, double*, double)>'
Указатель на функцию предоставляет то, что я называю контекст преобразования. В нем четко указано, какая из перегрузок имеется в виду, в то время как std::function
не. Конструктор std::function
принимает любую вызываемую сущность и, таким образом, не предоставляет контекста для однозначного определения, какая перегрузка подразумевается. Смотрите также этот вопрос.
Чтобы устранить неоднозначность вручную, либо приведите указатель на функцию
apply2(v, static_cast<void(*)(double*,double*,double)>(std::iota));
или использовать указатель на именованную функцию
void (*iota)(double*, double*, double) = std::iota;
apply2(v, iota);
или используйте лямбду
apply2(v, [](double* f, double* l, double d){ std::iota(f, l, d); });
Других решений пока нет …