Ответ 1
Короче говоря, используйте std::function
, если у вас нет причин для этого.
Указатели функций имеют недостаток неспособности захватить некоторый контекст. Вы не сможете, например, передать лямбда-функцию в качестве обратного вызова, который захватывает некоторые переменные контекста (но он будет работать, если он не фиксирует какой-либо). Таким образом, вызов элементарной переменной объекта (т.е. Нестатический) также невозможен, поскольку объект (this
-pointer) должен быть захвачен. (1)
std::function
(поскольку С++ 11) в первую очередь относится к хранить функцию (ее передача не требует ее сохранения). Следовательно, если вы хотите сохранить обратный вызов, например, в переменной-члене, это, вероятно, ваш лучший выбор. Но также, если вы его не храните, это хороший "первый выбор", хотя у него есть недостаток в том, что он вводит некоторые (очень маленькие) накладные расходы при вызове (поэтому в очень критичной для производительности ситуации это может быть проблемой, но в большинстве случаев он не должен). Это очень "универсальный": если вы много заботитесь о совместимом и читаемом коде, а также не хотите думать о каждом выбранном вами выборе (т.е. Хотите, чтобы это было просто), используйте std::function
для каждой функции, которую вы проходите.
Подумайте о третьем варианте: если вы собираетесь реализовать небольшую функцию, которая затем сообщает что-то через предоставленную функцию обратного вызова, рассмотрите параметр template, который может быть любым вызываемым объектом, т.е. указатель функции, функтор, лямбда, std::function
,... Недостатком здесь является то, что ваша (внешняя) функция становится шаблоном и, следовательно, должна быть реализована в заголовке. С другой стороны, вы получаете преимущество в том, что вызов обратного вызова может быть встроен, так как клиентский код вашей (внешней) функции "видит" вызов обратного вызова будет иметь доступную точную информацию о типе.
Пример для версии с параметром шаблона (напишите &
вместо &&
для pre-С++ 11):
template <typename CallbackFunction>
void myFunction(..., CallbackFunction && callback) {
...
callback(...);
...
}
Как вы можете видеть в следующей таблице, все они имеют свои преимущества и недостатки:
+-------------------+--------------+---------------+----------------+
| | function ptr | std::function | template param |
+===================+==============+===============+================+
| can capture | no(1) | yes | yes |
| context variables | | | |
+-------------------+--------------+---------------+----------------+
| no call overhead | yes | no | yes |
| (see comments) | | | |
+-------------------+--------------+---------------+----------------+
| can be inlined | no | no | yes |
| (see comments) | | | |
+-------------------+--------------+---------------+----------------+
| can be stored | yes | yes | no(2) |
| in class member | | | |
+-------------------+--------------+---------------+----------------+
| can be implemented| yes | yes | no |
| outside of header | | | |
+-------------------+--------------+---------------+----------------+
| supported without | yes | no(3) | yes |
| C++11 standard | | | |
+-------------------+--------------+---------------+----------------+
| nicely readable | no | yes | (yes) |
| (my opinion) | (ugly type) | | |
+-------------------+--------------+---------------+----------------+
(1) Существуют способы обхода этого ограничения, например, передача дополнительных данных в качестве дополнительных параметров для вашей (внешней) функции: myFunction(..., callback, data)
вызовет callback(data)
. Что C-стиль "обратный вызов с аргументами", который возможен в С++ (и, кстати, сильно используется в WIN32 API), но его следует избегать, потому что у нас есть лучшие варианты на С++.
(2) Если мы не говорим о шаблоне класса, т.е. класс, в котором вы храните эту функцию, является шаблоном. Но это будет означать, что на стороне клиента тип функции определяет тип объекта, который хранит обратный вызов, который практически никогда не является вариантом для фактических случаев использования.
(3) Для pre-С++ 11 используйте boost::function