A lambda expression creates a function-like object with some optional additional state. The call signature is determined by the lambda parameters, and the additional state is determined by the capture clause.
Now the signature you need to create is not always your choice. If you are passing your lambda to a standard or third-party API, then the API requires your lambda to have a certain signature. If tgere is any data you want to pass in addition to the imposed signature, you need to capture it.
Consider a well known example from the C library: the qsort function.
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*));
The comparator function accepts pointers to the two objects being compared and that's it. There is no way to pass an additional flag that would control how exactly the comparison is done. As an example, consider sorting a list of words in some natural language according to the collation rules of that language, determined at runtime. How do you tell your comparator which language to use? The only option with this API is to set the language in a static variable (yikes).
Because of this well known shortcoming, people are defining various non-standard substitute APIs. For example
void qsort_r(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *, void *),
void *arg);
I hope you recognise what's going on. You pass an additional argument (the language identifier or whatever) as arg
, then the sort function forwards it as a sealed package to your comparator. It then casts the argument to its original type and uses it
Enter C++. In std::sort
, the comparator is a function like object that carries its own state. So this trick is unnecessary. You define something like
struct LanguageSensitiveComparator
{
LanguageSensitiveComparator(LangauageID lang) : lang(lang) {}
LangauageID lang;
bool operator()(const string& a, const string& b) const { .... } // etc
};
sort(dict.begin(), dict.end(), LanguageSensitiveComparator(lang));
C++11 takes its a step further. Now you can define the function object on the spot, using a lambda.
sort (begin(dict), end(dict),
[=lang](const string& a, const string& b) { .. });
Back to your question. Could you pass lang as an argument instead of capturing it? Sure, but you would need to define your own sort that knows about an additional LabguageID parameter (that's what qsort_r basically does, except it's not type safe).
std
methods use (eg find_if etc). The lambda condenses the syntax to allow the predicate and lambda to be in the same expression. Previously this would require a class (template) decaration (at global scope), initialisation of the class object and final passing the object into the predicate. – Marry