Как правило, функторы передаются в шаблонные функции - если вы это делаете, то не имеет значения, если вы передаете "реальную" функцию (т.е. указатель функции) или функтор (т.е.класс с перегруженным operator()
).По сути, оба имеют оператор вызова функции и, следовательно, являются допустимыми параметрами шаблона, для которых компилятор может создать экземпляр шаблона for_each
. Это означает, что for_each
создается либо с конкретным типом переданного функтора, либо с конкретным типом переданного указателя функции. И это в той специализациичто функторы могут превосходить указатели на функции.
В конце концов, если вы передаете указатель на функцию , тогда тип аргумента типа компиляции - это просто указатель на функцию.Если сам for_each
не является встроенным, то этот конкретный экземпляр for_each
компилируется для вызова непрозрачного указателя на функцию - в конце концов, как компилятор может встроить указатель на функцию?Он просто знает свой тип , а не , какую функцию этого типа фактически передают - по крайней мере, если он не может использовать нелокальную информацию при оптимизации, что сложнее сделать.
Однако, если вы передаете функтор , то тип времени компиляции этого функтора используется для создания экземпляра шаблона for_each
.При этом вы, вероятно, передаете простой, не виртуальный класс только с одной реализацией соответствующего operator()
.Таким образом, когда компилятор встречает вызов operator()
, он точно знает, какая реализация подразумевается - уникальная реализация для этого функтора - и теперь он может встроить это.
Если ваш функтор использует виртуальные методы, потенциальное преимуществоисчезает.И, конечно же, функтор - это класс, с помощью которого вы можете выполнять любые другие неэффективные действия.Но в базовом случае именно поэтому компилятору проще оптимизировать и встроить вызов функтора, чем вызов указателя функции.
Сводка
Указатели на функции нельзя встроить, поскольку при компиляцииfor_each
компилятор имеет только тип функции, а не идентификатор функции.В отличие от этого, функторы могут быть встроенными, поскольку, хотя компилятор имеет только тип функтора, его обычно достаточно для однозначной идентификации метода operator()
функтора.