CPP Functional Programming
CPP Functional Programming
double add(double d1, double d2) bool and(bool b1, bool b2)
{ return d1 + d2; } { return (b1 && b2); }
double dotProduct(Vector const & v1, bool areEqual (Vector const & v1,
Vector const & v2, size_t size) Vector const & v2, size_t size)
{ {
return engine(add, mult, 0.0, return engine(and, eq, true,
v1, v2, size); v1, v2, size);
} }
Case Study 2: Numerical Integration
using functional = double (*)(double);
double integrate(functional f, double begin, double end,
double step) {
double result = 0.0;
for (size_t i = 0; begin + double(i) * step < end; i++) {
result += f(begin + double(i) * step) * step;
}
return result;
}
double square(double x) { return x * x; }
double integral = integrate(&square, 0.0, 3.0, 0.001);
protected:
virtual double getSpecialData() = 0;
};
Case Study 2: Integrator Functional Object
using functional = class Integrator {
double (*)(double); public:
Integrator(functional f,
double integrate(functional f, double begin, double step);
double begin, double end,
double step); double operator()(double x) const
{
return integrate(mIntegrand,
mBegin, x, mStep);
}
private:
functional mIntegrand;
double mBegin;
double mStep;
};
Case Study 2: Integrator Functional Object
with Template
using functional = template<class TIntegrand>
double (*)(double); double templateIntegrate(
double integrate(functional f, TIntegrand const & integrand,
double b, double e, double s); double b, double e, double s)
class Integrator { {
public: double result = 0.0;
Integrator(functional f, for (size_t i = 0;
double b, double s);
b + double(i) * s < e; i++) {
double operator()(double x) const; result += integrand(
private: b + double(i) * s) * s;
// see above... }
}; return result;
}
What Did We Learn So Far?
• In classical functional programming, everything is a function.
• The simplest form of a functional object in C++ (and C!) is a function
pointer.
• In C++ the notion of a functional object can be expressed by an
overloaded operator() or, in a broader sense, by overridden virtual
methods.
• Functional objects are an essential element of generic programming,
e.g.
• Code template (functions, classes)
• Design patterns (Template Method, Observer, …)
Part 2: C++11 Functional Objects
Functional Object Categories in C++11+
Category Form / Example
Global function pointers using functional = double (*)(double);
Member function pointers class MyClass { double someMethod(double); };
using MFunc = double (MyClass::*)(double);
MFunc f = &MyClass::someMethod;
MyClass obj;
double v = (obj.*f)(5.0);
“Crafted” functional class class Integrator { double operator()(double); };
Virtual methods class Algorithm { virtual double f(double) = 0; };
std::bind objects auto integrator = std::bind(integrate, square,
0.0, std::placeholders::_1, 0.001);
double integral = integrator(3.0);
Lambda objects auto f = [](double x) { return x * x; };
double v = f(5.0);
std::function using functor = std::function<double(double)>;
functor f = /* most of the above...*/;
double v = f(5.0);
Argument Binding
• “Bind” is an “operator” on a functional object and other parameters, which returns
another functional object:
double add(double x, double y) { return x + y; }
auto add10 = std::bind(add, _1, 10.0); // _1 is a placeholder for an argument passed to add10
• In this example, “add” is the bound functional object, and “add10” is the binding
functional object.
• add10.operator() takes one parameter and forwards it to the bound functional
along with a bound argument, which happens to be 10.0. ➔ Effectively, “add10” is a
unary functional object.
• The roots of “bind” go back to Lambda Calculus – a theoretical model of computability
and functional programming.
• The C++ syntax and usage rules of std::bind are (subjectively) cryptic and often
confusing.
• Clang-Tidy recommends to “prefer a lambda to std::bind”, and I join.
Lambda Objects
• The term “Lambda” comes from Lambda Calculus (LC), mentioned
above, where it represents a functional.
• C++11+ defines a new syntax (“syntactic sugar”) for instantiation of
functional objects, which can replace most of the hand-crafted
overloads of operator(), and simultaneously add bind capabilities.
These objects are “lambda objects” or just “lambdas”.
• C++ lambdas are slightly abusing the original LC lambdas because
they are real objects, they can mutate a global program state, and can
even have a mutable state of their own.
• But it’s a catchy name and the abuse is small, and if they’re
immutable, well, it’s close enough.
What’s in a Lambda?
• Much more detail and examples in Andreas Fertig’s presentation of Core C++
2019: https://www.andreasfertig.info/talks_dl/afertig-corecpp-2019-cpp-
lambdas-demystified.pdf
• Here’s the short of it.
double add(double x, double y) { return x + y; }
void myFunction() {
double num = 10.0; capture