template<typename Func> void MyFunc (const Func & otherFunc);
void MyFunc (const std::function<void()> & otherFunc);
Это очень разные ситуации. Во-первых, в первом случае функция будет шаблонной. С шаблонными и нешаблонными функциями нужно обращаться по-разному, я думаю вы уже знаете как и почему. Код первого (шаблонного) варианта будет компилиться только при использовании MyFunc, и большинство проверок типов будет происходить именно в этот момент. Ну и понятное дело, шаблонный вариант нужно класть в хедер.
С другой стороны, почему-то никто не упомянул такую важную разницу:
class overloaded_functor {
public:
bool operator()(int a) const { return a > 10; }
bool operator()(double a) const { return a > 10.0; }
bool operator()(const std::string& a) const { return a.size() > 10; }
};
template <typename Func>
void foo(Func f) {
// Все варианты компилятся и работают (т.к. сама шаблонная функция foo и все применения оператора вызова к f компилятся ПОСЛЕ того как мы написали foo(overloaded_functor()) );
f(3);
f(5.4);
f("Blah");
}
void bar(std::function<bool(int)> f) {
f(3);
// Компилится, но, как и ожидаемо, конвертит double к int, чего мы в нашем случае не хотим
f(5.4);
// Не компилится вовсе
f("Blah");
}
...
foo(overloaded_functor());
bar(overloaded_functor());
std::function по-определению требует указания конкретного типа функции/функтора, которую он оборачивает, поэтому std::function не может работать с перегруженным функтором. Это не так часто нужно, но бывает, например visitor часто реализуется именно таким функтором с несколькими вариантами оператора вызова.
На всякий случай отмечу, что я ни в коем случае не говорю, что std::function недостаточно мощный вариант. Наоборот, его нужно использовать в большинстве случаев, т.к. в большинстве случаев нужно функция конкретного типа (конкретной сигнатуры и конкретного возвращаемого значения). Однако разницу следует понимать, т.к. эти варианты используются в разных ситуациях.
Ну и понятное дело, обычный указатель на функцию неудобен, т.к. не позволяет захватить контекст. В Сях для этого существует паттерн userData, и всякий разработчик библиотеки, которая использует callback-и, реализует этот паттерн. В Плюсах для этого есть std::function.