Functional Programming in C++: Advanced Techniques and Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Functional Programming in C++: Advanced Level

\n\n

Functional programming (FP) is a paradigm that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data. Although C++ is traditionally associated with object-oriented and procedural programming, modern standards (C++11 and later) have introduced powerful tools for writing functional code. In this article, we will go beyond basic lambdas and explore advanced techniques: from function composition to emulating monads.

\n\n

1. Function Composition and Pipelines

\n\n

Function composition is the process of combining two or more functions to create a new function. In C++, lambda expressions and templates are convenient for this purpose.

\n\n
#include <iostream>\n#include <functional>\n#include <vector>\n#include <algorithm>\n\n// Template for composing two functions\ntemplate<typename F, typename G>\nauto compose(F f, G g) {\n    return [f, g](auto x) {\n        return f(g(x));\n    };\n}\n\n// Usage example\nint main() {\n    auto addTwo = [](int x) { return x + 2; };\n    auto multiplyByThree = [](int x) { return x * 3; };\n\n    // Composition: first multiplyByThree, then addTwo\n    auto composed = compose(addTwo, multiplyByThree);\n\n    std::cout << composed(5) << std::endl; // (5*3) + 2 = 17\n\n    // Pipeline processing using std::ranges (C++20)\n    std::vector<int> numbers = {1, 2, 3, 4, 5};\n    auto result = numbers\n        | std::views::filter([](int n) { return n % 2 == 0; })\n        | std::views::transform([](int n) { return n * n; });\n\n    for (int n : result) {\n        std::cout << n << " "; // 4 16\n    }\n    return 0;\n}\n
\n\n

Pipelines with std::views (C++20) allow building transformation chains without creating intermediate containers, which is a classic functional approach.

\n\n

2. Currying and Partial Application

\n\n

Currying is the transformation of a function that takes multiple arguments into a sequence of functions, each taking a single argument. Partial application fixes some of the arguments.

\n\n
#include <iostream>\n#include <functional>\n\n// Curried addition function\nauto curriedAdd = [](int a) {\n    return [a](int b) {\n        return [a, b](int c) {\n            return a + b + c;\n        };\n    };\n};\n\n// Partial application using std::bind\nint multiply(int a, int b, int c) {\n    return a * b * c;\n}\n\nint main() {\n    // Using currying\n    auto add5 = curriedAdd(5);\n    auto add5And3 = add5(3);\n    std::cout << add5And3(2) << std::endl; // 10\n\n    // Partial application via std::bind\n    using namespace std::placeholders;\n    auto multiplyBy2 = std::bind(multiply, _1, _2, 2);\n    std::cout << multiplyBy2(3, 4) << std::endl; // 3*4*2 = 24\n\n    // Partial application via lambda (more idiomatic in C++14+)\n    auto multiplyBy3 = [](int a, int b) { return multiply(a, b, 3); };\n    std::cout << multiplyBy3(5, 6) << std::endl; // 5*6*3 = 90\n\n    return 0;\n}\n
\n\n

Currying is especially useful when working with higher-order functions such as std::transform or std::accumulate, allowing you to create specialized versions of functions "on the fly."

\n\n

3. Functors, Applicatives, and Emulating Monads

\n\n

In Haskell, monads are a powerful pattern for handling side effects. In C++, we can emulate them using class templates. Let's consider a simple Maybe monad (analogous to std::optional), but with monadic operations.

\n\n
#include <iostream>\n#include <functional>\n#include <optional>\n\n// Maybe monad (wrapper over std::optional)\ntemplate<typename T>\nclass Maybe {\n    s                

Blogs

Book Recommendations