C++ 中的函数式编程:高级进阶
函数式编程是一种将计算表示为数学函数求值的范式,旨在避免状态变更和可变数据。尽管 C++ 最初是面向对象和过程式语言,但从 C++11 标准开始,它获得了强大的函数式编程工具:lambda 表达式、std::function、std::bind,而 C++17 则增加了对 std::optional 和 std::variant 的支持,使得实现单子模式成为可能。在本文中,我们将探讨 C++ 中的高级函数式编程技术:函数合成、柯里化、单子操作,以及利用现代语言特性创建纯函数。
1. Lambda 表达式与纯函数
Lambda 表达式是 C++ 中函数式风格的基础。它们允许即时创建匿名函数,非常适合用于 <algorithm> 中的算法。然而,对于真正的函数式编程而言,lambda 必须是纯的——即没有副作用,且不依赖于外部可变状态。
#include <iostream>#include <vector>#include <algorithm>
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5};
// 纯 lambda:仅输入数据,仅输出结果 auto square = [](int x) { return x * x; };
// 无副作用地应用变换 std::vector<int> squared; std::transform(numbers.begin(), numbers.end(), std::back_inserter(squared), square);
for (int n : squared) std::cout << n << " "; // 1 4 9 16 25 return 0;}在高级应用中,除非必要,应避免按引用捕获([&])。按值捕获([=])或显式列举捕获项能使 lambda 更具可预测性和可测试性。
2. 使用 std::function 与运算符进行函数合成
合成是指将两个或多个函数组合成一个函数。在 C++ 中,可以通过模板和 std::function 来实现合成。让我们看一个通用的合成器:
#include <functional>#include <iostream>
template <typename F, typename G>auto compose(F f, G g) { return [f, g](auto x) { return f(g(x)); };}
int main() { auto addOne = [](int x) { return x + 1; }; auto multiplyByTwo = [](int x) { return x * 2; };
auto addThenMultiply = compose(multiplyByTwo, addOne); std::cout << addThenMultiply(5) << std::endl; // (5+1)*2 = 12
// 多个函数的合成 auto triple = compose(multiplyByTwo, compose(addOne, addOne)); std::cout << triple(5) << std::endl; // ((5+1)+1)*2 = 14 return 0;}对于更复杂的链式操作,可以使用管道运算符(类似其他语言中的 |>)。在 C++20 中,可以通过重载 operator| 来创建便捷的语法:
#include <functional>#include <iostream>
template <typename F>class Pipeable { F f;public: Pipeable(F func) : f(func) {} template <typename T> auto operator()(T x) const { return f(x); }};
template <typename T, typename F>auto operator|(T x, Pipeable<F> p) { return p(x);}
int main() { auto addOne = Pipeable([](int x) { return x + 1; }); auto square = Pipeable([](int x) { return x * x; });
int result = 5 | addOne | square; // (5+1)^2 = 36 std::cout << result << std::endl; return 0;}这种方法使代码具有声明式风格,易于阅读。
3. 柯里化与部分应用
柯里化是将一个接受多个参数的函数转换为