Saturday, December 16, 2017

C++ with lambda

The following code is a legal declaration of a lambda:

auto aLambda = [](){};

The challenges are filling in the blanks, ie, defining the lambda so it meets expectations in regards to parameters and return value.
•  auto is a C++ keyword that says the type will be determined by the compiler
•  aLambda is the name we have assigned this particular lambda
•  [] context; often no value is coded here
•  () parameters to the lambda function
•  {} the lambda function's code goes

Here I use a lambda with the standard library function accumulate to total the prices of jam, jelly and peanut butter. Three examples are shown in order to demonstrate three slightly different techniques.
#include <numeric>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

struct Item {
  string name;
  double price;
};
double getPrice(Item i) { return i.price;};

vector inventory = {{"jam", 4.29}, {"jelly", 3.24}, {"peanut butter", 3.99}};

int main() {
  double result;

  // ex 1: declare a lambda and assign it to a var and use the var in the accumulate function.
  auto accumPrices = [](double j, const Item k) -> double {return j + getPrice(k);};
  result = accumulate(inventory.begin(), inventory.end(), 0.0, accumPrices);
  cout << result << endl;

  // ex 2: same as first example but lambda calc accesses price directly from struct
  auto accumFunc = [](double j, const Item k) -> double {return j + k.price;};
  result = accumulate(inventory.begin(), inventory.end(), 0.0, accumFunc);
  cout << result << endl;

  // ex 3: insert the lambda directly into the accumulate function
  cout <<
    accumulate(inventory.begin(), inventory.end(), 0.0, 
      [](double dbl, Item i){return dbl + i.price;})
  << endl;
}

Compile & Run
$ g++ -std=c++14 -c -o genItems.o genItems.cpp
$ g++ -o genItems genItems.o
$ ./genItems
11.52
11.52
11.52
$

Filter With Lambda
#include <numeric>
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

struct Item {
  string name;
  double price;
};
double getPrice(Item i) { return i.price;};

int main() {
  vector<Item> inventory = {{"jam", 4.29}, {"jelly", 4.24}, {"peanut butter", 3.99}};
  vector<Item> results;
  copy_if(
    inventory.begin(), inventory.end(), back_inserter(results), 
      [](Item i){return getPrice(i) > 4.00;}  // add to list if price > $4.00
  );
  for(Item i : results) {
    cout << i.name << endl;
  }
}
$ g++ -std=c++14 -c -o VectorFilter.o VectorFilter.cpp
$ g++ -o VectorFilter VectorFilter.o
$ ./VectorFilter
jam
jelly
$ 

"Add-on" Lambda

Here we use some more features of lambdas.
•  We will define and call a lambda in one line of code. It is very similar to Javascript.
•  The ampersand in the square brackets [&] is used in my examples for the first time. It allows the lambda access to variables defined outside of its own scope.
•  Inside the lambda's parentheses int a is declared so that a parm can be passed to the lambda.
•  At the end of the lambda (my_parm) causes the lambda to be called with parm passed in to the parameter a.
#include <iostream>
using namespace std;

int main() {
  int m = 4, result = 0;
  int my_parm = 7;
  result = [&](int a){ return a + m; }(my_parm);
  cout << result << endl;
}