The count_if function is one of many provided by the standard template library (STL). It operates on a collection of strings, ints or other data types and it expects to be passed a function that will perform the test the program requires. This test is called the predicate. In the first code example, the predicate is defined as a traditional function. The call to the count_if function only references the mypredicate function, it isn't called at the point where it is coded but is used internally within the count_if function.
#include <iostream> #include <string> #include <vector> using namespace std; int mypredicate(const string& str) { return "T" == str.substr(0,1); } // This program determines how many of the names in a list begin with the letter "T". int main() { vector<string> names = {"Sam", "Ben", "Ted", "Joe", "Tim"}; cout << count_if(names.begin(), names.end(), mypredicate) << endl; return 0; }
The compile, link and run are performed with the following commands.
$ g++ -std=c++14 -c -o count_names.o count_names.cpp $ g++ -o count_names count_names.o $ ./count_names 2
In the next code example, the predicate is no longer a traditional function but is defined as a lambda, an in-line function declaration. It is defined at the point where it is called.
The count_if function has 3 parameters, the vector start (in yellow) and end (in blue) and the predicate (in violet) which is a function. Here the function is coded as a lambda.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
vector<string> names = {"Sam", "Ben", "Ted", "Joe", "Tim"};
cout << count_if(
names.begin(),
names.end(),
[](string s){return "T" == s.substr(0,1);}
)
<< endl;
return 0;
}
The value of this functional code is that (1.) it is less code, (2.) it is declarative code, (3.) it eliminates the details of the boiler plate of the for loop and, by eliminating the detail, gives us code that conforms to the Single Level of Abstraction Principle.
Because functions must be first class objects in functional programming we should prove that a lambda can be created in one place and used in another, just like any other var. In the code below we define the predicate as a lambda with the name mypredicate and use it later. This is similar to the code in the first example but we replace the funcion with a lambda.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
auto mypredicate = [](string s){return "T" == s.substr(0,1);};
vector<string> names = {"Sam", "Ben", "Ted", "Joe", "Tim"};
cout << count_if(
names.begin(),
names.end(),
mypredicate
)
<< endl;
return 0;
}
The difference between declaring a lambda and calling a lambda.
#include <iostream>
int main() {
std::cout << [](){return 42;} << std::endl; // prints 1
std::cout << [](){return 42;}() << std::endl; // prints 42
}