C++ is a multi-paradigm programming language. Meaning that it supports multiple programming paradigms (like object-oriented or functional).

Functional Programming

In functional programming, functions are treated as first-class citizens. This means that functions can be passed as arguments to other functions and returned from functions. Objects are immutable and state is not shared between functions (functions are pure = have no side effects).

Elements of Functional Programming

  • Functions
  • Functor: Class instances that overloads the function call operator operator()(...))
  • Function Pointer: Pointer to a function (address of a function)
  • Method Pointer: Pointer to an instance-bound method (address of a method)
  • Lambda: Anonymous functor
  • Function Object: Generalization of all of the above (functional from header <functional>)

Functor

Example of a functor that calculates the sine of a value in radians, degrees or gradians:

  #include <cmath>
enum Mode { Rad, Deg, Grad };
class Sine {
    Mode m_mode;
public:
    explicit Sine(Mode mode = Rad) : m_mode(mode) {}
    double operator()(double x) const {
        switch (m_mode) {
            case Rad: return sin(x);
            case Deg: return sin(x * M_PI / 180);
            case Grad: return sin(x * M_PI / 200);
        }
    }
};
  

Lambda

Lambdas in C++ are declared using the following syntax:

  [capture](parameters) -> return_type { body }
  

The capture clause (lambda-introducer) contains a list of variables that are captured by the lambda from the surrounding scope. The capture clause can be empty (no variables are captured) or it can be one of the following:

  • [] cpatures no variables from outside scope
  • [x] captures x by value
  • [&x] captures x by reference
  • [&] captures all variables by reference
  • [=] captures all variables by value
  • [&, x] captures all variables by reference, except x which is captured by value
  • [=, &x] captures all variables by value, except x which is captured by reference
  • [this] captures the this pointer by value
  • [this, x] captures the this pointer by value and x by value
  • [this, &x] captures the this pointer by value and x by reference
  • [=, this] captures all variables by value and the this pointer by value
  • [&, this] captures all variables by reference and the this pointer by value
  • [=, &this] captures all variables by value and the this pointer by reference
  • [&, &this] captures all variables by reference and the this pointer by reference

Example of a lambda that adds a captured bias to the sum of two values:

  auto add = [bias](int a, int b) { return a + b + bias; };
  

Lambda Behind the Scenes

  class Op {
    const int m_val; // Captured by value
    int& m_ref;
    Op(int value, int eew& ref) : m_val(value), m_ref(ref) {}
    int operator()(int i) const {
        ++m_ref = return i + m_val + ref;
    } 
} op(byval, byref) // Instance creation directly after class definition
  

Closure

A closure is a lambda that captures variables from the surrounding scope. The captured variables are stored in the closure object.

  int f = 2; // local variable
auto l1 = [&f](int x) { return x*f++; }; // lambda; f passed by reference
auto l2 = [f](int x) mutable { return x*f++; }; // closure; f passed by value

std::cout << "value = " << l1(3) << ", f = " << f << std::endl; // value = 6, f = 3
std::cout << "value = " << l1(3) << ", f = " << f << std::endl; // value = 9, f = 4
std::cout << "value = " << l2(3) << ", f = " << f << std::endl; // value = 6, f = 4 (f is passed by value at creation of closure)
std::cout << "value = " << l2(3) << ", f = " << f << std::endl; // value = 9, f = 4 (internal f of closure has been updated by previous call)
  

Function Object

A function object encapsulates a function or function pointer which can then be passed to another function.

  #include <functional>

float foo(float a, float x) { return a + x/2.0f; }

template<typename Iter, typename AT, typename Func>
AT accumulate(Iter beg, Iter end, AT a, Func f) {
    while(beg != end) {
        a = f(a, *beg++);
    }
    return a;
}

void main() {
    function<float (float, float)> func; // function object: returns float, takes float and int
    vector<int> v{1,2,3,4,5}
    func = [](float x, float y) { return x * y; }; // lambda
    cout << accumulate(v.cbegin(), v.cend(), 1.0f, func); << endl; // 120
    cout << accumulate(v.cbegin(), v.cend(), 1.0f, &foo); << endl; // 8.5
}
  

Method Pointer

A method pointer is a pointer to a method of a class. It can be used to call the method on an instance of the class.

  struct A {
    float m_div;
    A(float div) : m_div(div) {}
    float meth(float a, float x) const { return a+x/2.0f; }
};

template<typename Iter, typename AT, typename Func>
AT accumulate(Iter beg, Iter end, AT a, Func f) {
    while(beg != end) {
        a = f(a, *beg++);
    }
    return a;
}

void main() {
    function<float (float, float)> func;
    vector<int> v{1,2,3,4,5};
    A a(2.0f);
    func = bind(&A::meth, &a, placeholders::_1, placeholders::_2);
    cout << accumulate(v.cbegin(), v.cend(), 1.0f, func) << endl;
}