这是因为 lambda 是 函数对象,因此将它们传递给函数模板将会为该对象实例化一个新的函数。编译器可以轻松地内联 lambda 调用。
另一方面,对于函数来说,旧的警告依然适用:函数 指针 会被传递给函数模板,传统上编译器通过函数指针进行调用时会有许多问题。理论上,它们可以被内联,但只有在周围的函数也被内联的情况下才能实现。
例如,请考虑以下函数模板:
template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
使用 lambda 进行调用,如下所示:
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 ()
并且可以轻松地内联调用它。(而使用任何其他lambda调用函数map
都会创建map
的新实例,因为每个lambda具有不同的类型。)
但是,当使用函数指针调用时,实例化的情况如下:
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
解析为一个特定的函数。