Lý do là lambdas là các đối tượng chức năng nên việc chuyển chúng vào một mẫu hàm sẽ khởi tạo một chức năng mới dành riêng cho đối tượng đó. Do đó, trình biên dịch có thể nội tuyến một cách tầm thường cuộc gọi lambda.
Mặt khác, đối với các hàm, cảnh báo cũ được áp dụng: một con trỏ hàm được chuyển đến mẫu hàm và các trình biên dịch theo truyền thống có rất nhiều vấn đề khi thực hiện các cuộc gọi thông qua các con trỏ hàm. Về mặt lý thuyết chúng có thể được nội tuyến, nhưng chỉ khi chức năng xung quanh cũng được nội tuyến.
Ví dụ, xem xét mẫu hàm sau:
template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
Gọi nó bằng lambda như thế này:
int a[] = { 1, 2, 3, 4 };
map(begin(a), end(a), [](int n) { return n * 2; });
Kết quả trong phần khởi tạo này (được tạo bởi trình biên dịch):
template <>
void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) {
for (; begin != end; ++begin)
*begin = f.operator()(*begin);
}
Trình biên dịch biết _some_lambda_type::operator ()và có thể gọi nội tuyến một cách tầm thường. (Và việc gọi hàm mapvới bất kỳ lambda nào khác sẽ tạo ra một khởi tạo mới mapvì mỗi lambda có một loại riêng biệt.)
Nhưng khi được gọi bằng một con trỏ hàm, phần khởi tạo trông như sau:
template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
Càng và ở đây fchỉ đến một địa chỉ khác nhau cho mỗi cuộc gọi mapvà do đó trình biên dịch không thể gọi nội tuyến ftrừ khi cuộc gọi xung quanh mapcũng đã được nội tuyến để trình biên dịch có thể phân giải fthành một chức năng cụ thể.