Il motivo è che le lambda sono oggetti funzione, quindi passandoli a un modello di funzione verrà creata un'istanza di una nuova funzione specifica per quell'oggetto. Il compilatore può quindi banalmente incorporare la chiamata lambda.
Per le funzioni, d'altra parte, si applica il vecchio avvertimento: un puntatore a funzione viene passato al modello di funzione, e tradizionalmente i compilatori hanno molti problemi nell'allineare le chiamate tramite puntatori a funzione. In teoria possono essere incorporati, ma solo se anche la funzione circostante è incorporata.
Ad esempio, considerare il seguente modello di funzione:
template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
Chiamandolo con un lambda come questo:
int a[] = { 1, 2, 3, 4 };
map(begin(a), end(a), [](int n) { return n * 2; });
Risultati in questa istanza (creato dal compilatore):
template <>
void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) {
for (; begin != end; ++begin)
*begin = f.operator()(*begin);
}
... il compilatore conosce _some_lambda_type::operator ()
e può incorporare le chiamate in modo banale. (E invocare la funzione map
con qualsiasi altra lambda creerebbe una nuova istanza map
poiché ogni lambda ha un tipo distinto.)
Ma quando viene chiamato con un puntatore a funzione, l'istanza appare come segue:
template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
... e qui f
indica un indirizzo diverso per ogni chiamata a map
e quindi il compilatore non può incorporare le chiamate a f
meno che anche la chiamata circostante a map
sia stata incorporata in modo che il compilatore possa risolvere f
una specifica funzione.