C++中的函数式编程:从Lambda到组合
函数式编程(FP)是一种基于纯函数应用、数据不可变性和无副作用构建计算的编程范式。虽然C++最初是一种多范式语言,但现代标准(C++11/14/17/20)引入了强大的FP工具:lambda表达式、std::function、STL算法、协程,甚至支持单子模式。在本文中,我们将探讨如何在不损失性能的情况下用C++编写函数式代码。
1. 函数式风格基础:Lambda和std::function
Lambda表达式是C++中FP的核心。它们允许你"即时"创建匿名函数并捕获上下文。
#include <iostream>#include <vector>#include <algorithm>
int main() { std::vector<int> nums = {1, 2, 3, 4, 5}; // 用于过滤偶数的Lambda auto is_even = [](int x) { return x % 2 == 0; }; // 与std::copy_if算法一起使用 std::vector<int> evens; std::copy_if(nums.begin(), nums.end(), std::back_inserter(evens), is_even); for (int n : evens) std::cout << n << " "; // 2 4 return 0;}关于Lambda的关键点:
- 捕获 —
[=](按值捕获)、[&](按引用捕获)、[this](用于类方法)。 - 类型 — 每个Lambda都有唯一类型,因此使用
std::function或模板来传递给函数。 - 返回值 — 除非另行指定,否则自动推导。
std::function — 可调用对象(函数、Lambda、仿函数)的包装器。便于存储和传递,但会增加开销(虚函数调用)。
#include <functional>
void apply_twice(std::function<int(int)> f, int x) { std::cout << f(f(x)) << std::endl; // 组合}
int main() { auto square = [](int x) { return x * x; }; apply_twice(square, 3); // (3^2)^2 = 81 return 0;}2. 作为函数式链基础的STL算法
STL算法(std::transform、std::copy_if、std::accumulate等)完美契合函数式风格。它们不直接修改容器,而是接受迭代器并返回结果。
示例:过滤和转换(map/filter)
#include <numeric>#include <ranges> // C++20
int main() { std::vector<int> data = {1, 2, 3, 4, 5, 6}; // 经典方法(C++11) std::vector<int> filtered; std::copy_if(data.begin(), data.end(), std::back_inserter(filtered), [](int x) { return x > 3; }); std::vector<int> result; std::transform(filtered.begin(), filtered.end(), std::back_inserter(result), [](int x) { return x * 2; }); // 使用范围(ranges)的现代方法(C++20) auto view = data | std::views::filter([](int x) { return x > 3; }) | std::views::transform([](int x) { return x * 2; }); for (int v : view) std::cout << v << " "; // 8 10 12 return 0;}使用std::accumulate进行折叠
#include <numeric>
int main() { std::vector<int> nums = {1, 2, 3, 4}; // 求和,初始值为0 int sum = std::accumulate(nums.begin(), nums.end(), 0, [](int a, int b) { return a + b; }); // 求积,初始值为1 int prod = std::acc