La razón es que las lambdas son objetos de función, por lo que pasarlas a una plantilla de función creará una nueva función específicamente para ese objeto. De este modo, el compilador puede en línea trivialmente la llamada lambda.
Para las funciones, por otro lado, se aplica la advertencia anterior: se pasa un puntero de función a la plantilla de función, y los compiladores tradicionalmente tienen muchos problemas para alinear llamadas a través de punteros de función. Teóricamente pueden estar en línea, pero solo si la función circundante también está en línea.
Como ejemplo, considere la siguiente plantilla de función:
template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
Llamándolo con una lambda como esta:
int a[] = { 1, 2, 3, 4 };
map(begin(a), end(a), [](int n) { return n * 2; });
Resultados en esta instanciación (creada por el compilador):
template <>
void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) {
for (; begin != end; ++begin)
*begin = f.operator()(*begin);
}
... el compilador sabe _some_lambda_type::operator ()y puede hacer llamadas en línea de manera trivial. (E invocar la función mapcon cualquier otra lambda crearía una nueva instancia de mapya que cada lambda tiene un tipo distinto).
Pero cuando se llama con un puntero de función, la instanciación se ve de la siguiente manera:
template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
… Y aquí fapunta a una dirección diferente para cada llamada mapy, por lo tanto, el compilador no puede hacer llamadas en línea a fmenos que la llamada a maptambién se haya en línea para que el compilador pueda resolver funa función específica.