Проблема в том, что вывод шаблона работает с точным соответствием по типу, без преобразований.
Вы передаете указатели на функции, которые отличаются от типа std::function
, поэтому вывод параметров шаблона будет fail.
Правильный способ - использовать вызываемые элементы в качестве аргументов шаблона. Это гарантирует, что вычет будет работать. Часто вам не нужно проверять сигнатуру вызываемого объекта, поскольку, если он используется в функции, вы получите ошибку времени компиляции, если он используется неправильно.
Если вы все еще хотите проверьте подпись, это не очень сложно сделать с чертой типа.
#include <string>
template<class A, class B>
B fmap(A a, B b) {
return a(b(std::string{}));
}
std::string function_1(int n);
double function_2(std::string s);
fmap(function_2, function_1);