C++ Reactive Programming
上QQ阅读APP看书,第一时间看更新

Functors and Lambdas

In classic C++, while using STL, we extensively use Function Objects or Functors by overloading Function Operators to write transformation filters and perform reduction on STL containers:

//----- LambdaThird.cpp
#include <iostream>
#include <numeric>
using namespace std;
//////////////////////////
// Functors to add and multiply two numbers
template <typename T>
struct addition{
T operator () (const T& init, const T& a ) { return init + a; }
};
template <typename T>
struct multiply {
T operator () (const T& init, const T& a ) { return init * a; }
};
int main()
{
double v1[3] = {1.0, 2.0, 4.0}, sum;
sum = accumulate(v1, v1 + 3, 0.0, addition<double>());
cout << "sum = " << sum << endl;
sum = accumulate(v1,v1+3,0.0, [] (const double& a ,const double& b ) {
return a +b;
});
cout << "sum = " << sum << endl;
double mul_pi = accumulate(v1, v1 + 3, 1.0, multiply<double>());
cout << "mul_pi = " << mul_pi << endl;
mul_pi= accumulate(v1,v1+3,1, [] (const double& a , const double& b ){
return a *b;
});
cout << "mul_pi = " << mul_pi << endl;
}

The following program clearly demonstrates the usage of Lambda by writing a toy sort program. We will show how we can use Function Objects and Lambdas to write equivalent code. The code is written in a generic manner, but it makes an assumption that numbers are expected (double, float, integer, or a user defined equivalent):

/////////////////
//-------- LambdaFourth.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//--- Generic functions for Comparison and Swap
template <typename T>
bool Cmp( T& a , T&b ) {return ( a > b ) ? true: false;}
template <typename T>
void Swap( T& a , T&b ) { T c = a;a = b;b = c;}

Cmp and Swap are generic functions that will be used to compare adjacent elements and swap elements, respectively, while performing the sort operation:

template <typename T>
void BubbleSortFunctor( T *arr , int length ) {
for( int i=0; i< length-1; ++i )
for(int j=i+1; j< length; ++j )
if ( Cmp( arr[i] , arr[j] ) )
Swap(arr[i],arr[j] );
}

Armed with Cmp and Swap, writing a bubble sort is a simple affair. We need to have a nested loop where we will compare two elements and if Cmp returns true, we will invoke Swap to exchange values:

template <typename T>
void BubbleSortLambda( T *arr , int length ) {
auto CmpLambda = [] (const auto& a , const auto& b )
{ return ( a > b ) ? true: false; };
auto SwapLambda = [] ( auto& a , auto& b )
{ auto c = a;a = b;b = c;};
for( int i=0; i< length-1; ++i )
for(int j=i+1; j< length; ++j )
if ( CmpLambda( arr[i] , arr[j] ) )
SwapLambda (arr[i],arr[j] );
}

In the preceding routine, we define the comparison and swap function as Lambdas. The Lambda function is  a mechanism to specify a piece of code or expression inline, often called anonymous functions. The definition can be given in a syntax specified by the C++ language, and can  be assigned to a variable, passed as a parameter , or returned from a function.  In the preceding function, the variables CmpLambda and SwapLambda are examples of anonymous functions specified in Lambda syntax. The body of the Lambda functions is not much different from the preceding function version. To learn more about Lambda functions and expression, you can consult the page at http://en.cppreference.com/w/cpp/language/lambda.

template <typename T>
void Print( const T& container){
for(auto i = container.begin() ; i != container.end(); ++i )
cout << *i << "\n" ;
}

The Print routine just cycles through the elements in the container and prints the contents to the console:

int main( int argc , char **argv ){
double ar[4] = {20,10,15,-41};
BubbleSortFunctor(ar,4);
vector<double> a(ar,ar+4);
Print(a);
cout << "=========================================" << endl;
ar[0] = 20;ar[1] = 10;ar[2] = 15;ar[3] = -41;
BubbleSortLambda(ar,4);
vector<double> a1(ar,ar+4);
Print(a1);
cout << "=========================================" << endl;
}