Generic Lambda in C++ 14 is a feature similar to templates. This was not present in C++11. In particular, the Generic lambda have auto in their parameter specification. This lambda can accept argument of any datatype, and indeed this is similar to templates.
The example showing this is as follows:
#include <iostream> //main header
using namespace std; //namespace
void funda(int xvar)
{
cout << "funda(int)" << endl;
}
void funda(double xvar)
{
cout << "funda(double)" << endl;
}
int main()
{
auto lambda = [](auto arg)
{
funda(arg);
};
int ivar = 9;
lambda(ivar);
lambda(4);
float jvar = 3.2;
lambda(jvar);
lambda(3.4);
return 0;
}
Output:
The C++11 compiler will not recognize this format.
Similar to template class
The generic lambda will have following template equivalent.
#include <iostream> //main header
using namespace std; //namespace
void funda(int xvar)
{
cout << "funda(int)" << endl;
}
void funda(double xvar)
{
cout << "funda(double)" << endl;
}
template<typename T>
void lambda(T arg)
{
funda(arg);
}
int main()
{
// auto lambda = [](auto arg)
// {
// funda(arg);
// };
int ivar = 9;
lambda(ivar);
lambda(4);
float jvar = 3.2;
lambda(jvar);
lambda(3.4);
return 0;
}
Generic lambda equivalent to Universal reference
To make a generic lambda equivalent to universal reference based template functions, following 3 conditions should be fulfilled.
- The parameter specification of lambda contains auto&&.
- Lambda shall use std::forward to forward the argument to either L-value or R-value overload
- std::forward shall use decltype of argument passed
auto&&
The semantics of auto&& is similar to universal reference template parameter, i.e., T&&. In such case, it will use reference collapsing rules to deduce the actual parameter type. This means, if an L-value argument is passed to lambda, then argument will deduce to become L-value reference. Similarly, it will become R-value reference when an R-value is passed as argument.
std::forward(decltype(arg)>
When parameter deduces to become an L-value reference, then std::forward shall forward it to L-value overload. This is because, in this case, the type specifier, decltype(arg) will return L-value type.
Similarly, when parameter deduces to become an R-value reference, then std::forward’s type specifier decltype(arg) shall return R-value type. Therefore, std::forward function shall forward the argument to R-value overload.
The following example demonstrates this
#include <iostream> //main header
using namespace std; //namespace
void funda(int& xvar)
{
cout << "funda(int&)" << endl;
}
void funda(int&& xvar)
{
cout << "funda(int&&)" << endl;
}
int main()
{
auto lambda = [](auto&& arg)
{
funda( std::forward<decltype(arg)>(arg) );
};
int ivar = 9;
lambda(ivar); //L-value passed
lambda(4); //R-value passed
return 0;
}
In first place, “i” is of L-value type “int&”, therefore, auto&&arg deduces to final type as shown:
auto&& arg => int& && arg => int& arg
In second place “4” is of R-value type “int&&”, therefore, auto&&arg deduces to final type as shown:
auto&& arg => int&& && arg => int&& arg
The output therefore, is as follows:
Similar to template function based on Universal reference
The following program is exactly equivalent to above lambda.
#include <iostream> //main header
using namespace std; //namespace
void funda(int& xvar)
{
cout << "funda(int&)" << endl;
}
void funda(int&& xvar)
{
cout << "funda(int&&)" << endl;
}
template<typename T>
void lambda(T&& arg)
{
fun( std::forward<T>(arg) );
}
int main()
{
//auto lambda = [](auto&& arg)
// {
// funda(std::forward<decltype(arg)>(arg));
// };
int ivar = 9;
lambda(ivar);
lambda(4);
return 0;
}
Output