Причина полягає в тому, що лямбди є функціональними об'єктами тому передача їх у шаблон функції буде інстанціювати нову функцію спеціально для цього об’єкта. Таким чином, компілятор може тривіально вбудувати лямбда-дзвінок.
Для функцій, з іншого боку, застосовується старий застереження: вказівник функції передається до шаблону функцій, а у компіляторів традиційно виникає багато проблем з викликом викликів за допомогою функціональних покажчиків. Вони теоретично можуть бути накресленими, але лише в тому випадку, якщо навколишня функція також вкладена.
Як приклад, розглянемо наступний шаблон функції:
template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
Називаючи це лямбда таким чином:
int a[] = { 1, 2, 3, 4 };
map(begin(a), end(a), [](int n) { return n * 2; });
Результати цієї інстанції (створеної компілятором):
template <>
void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) {
for (; begin != end; ++begin)
*begin = f.operator()(*begin);
}
… Компілятор знає _some_lambda_type::operator ()
і може вбудовувати дзвінки до нього тривіально. (А виклик функції map
з будь-якою іншою лямбдаю створив би нову інстанціюmap
оскільки кожна лямбда має різний тип.)
Але при виклику за допомогою вказівника функції екземпляр виглядає так:
template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
… І тут f
вказується на іншу адресу для кожного виклику до, map
і тому компілятор не може вбудовувати дзвінки, f
якщо оточуючий виклик map
також не був вкладений, щоб компілятор міг вирішити f
одну конкретну функцію.