Der Grund dafür ist, dass Lambdas Funktionsobjekte sind. Wenn Sie sie also an eine Funktionsvorlage übergeben, wird eine neue Funktion speziell für dieses Objekt instanziiert. Der Compiler kann somit den Lambda-Aufruf trivial inline.
Für Funktionen, andererseits gilt die alte Einschränkung: eine Funktion Zeiger auf die Funktionsvorlage übergeben wird, und Compiler haben traditionell eine Menge Probleme Anrufe über Funktionszeiger inlining. Sie können theoretisch inline sein, aber nur, wenn auch die umgebende Funktion inline ist.
Betrachten Sie als Beispiel die folgende Funktionsvorlage:
template <typename Iter, typename F>
void map(Iter begin, Iter end, F f) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
Nennen wir es mit einem Lambda wie diesem:
int a[] = { 1, 2, 3, 4 };
map(begin(a), end(a), [](int n) { return n * 2; });
Ergebnisse in dieser Instanziierung (vom Compiler erstellt):
template <>
void map<int*, _some_lambda_type>(int* begin, int* end, _some_lambda_type f) {
for (; begin != end; ++begin)
*begin = f.operator()(*begin);
}
… Der Compiler weiß _some_lambda_type::operator ()
und kann ihn trivial inline aufrufen. (Und das Aufrufen der Funktion map
mit einem anderen Lambda würde eine neue Instanziierung erzeugen, map
da jedes Lambda einen eigenen Typ hat.)
Beim Aufruf mit einem Funktionszeiger sieht die Instanziierung jedoch wie folgt aus:
template <>
void map<int*, int (*)(int)>(int* begin, int* end, int (*f)(int)) {
for (; begin != end; ++begin)
*begin = f(*begin);
}
… Und zeigt hier f
auf eine andere Adresse für jeden Aufruf von map
und daher kann der Compiler keine Inline-Aufrufe an senden , es f
sei denn, der umgebende Aufruf von map
wurde ebenfalls inline geschrieben, damit der Compiler f
in eine bestimmte Funktion auflösen kann .