Функциональное программирование в C++: современные возможности и примеры

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Функциональное программирование в C++: современные возможности и примеры

Функциональное программирование (ФП) — это парадигма, в которой вычисления рассматриваются как вычисление математических функций, избегающих изменения состояния и изменяемых данных. Хотя C++ традиционно ассоциируется с объектно-ориентированным и процедурным программированием, начиная с C++11 и особенно в C++14/17/20, язык получил мощные инструменты для функционального стиля. В этой статье мы разберем ключевые концепции, которые сделают ваш код на C++ более лаконичным, безопасным и выразительным.

1. Лямбда-выражения и замыкания

Лямбда-выражения — это анонимные функции, которые можно использовать на месте. Они стали основой функционального программирования в C++. Лямбда захватывает переменные из окружения (замыкание) и может быть передана в алгоритмы STL.

Синтаксис лямбда-выражения

auto lambda = [захват](параметры) -> возвращаемый_тип { тело };

Пример: сортировка с лямбдой

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> nums = {5, 2, 8, 1, 9};
    
    // Сортировка по убыванию
    std::sort(nums.begin(), nums.end(), 
              [](int a, int b) { return a > b; });
    
    for (int n : nums) std::cout << n << " "; // 9 8 5 2 1
    return 0;
}

Замыкания: захват по значению и ссылке

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    int threshold = 5;
    std::vector<int> data = {1, 6, 3, 8, 2};
    
    // Захват по значению [=] - копия threshold
    auto count_greater = std::count_if(data.begin(), data.end(), 
                                        [=](int x) { return x > threshold; });
    
    // Захват по ссылке [&] - можно изменять
    auto modify = [&](int &x) { 
        if (x < threshold) x += threshold; 
    };
    std::for_each(data.begin(), data.end(), modify);
    
    std::cout << "Count: " << count_greater << "\n"; // Count: 2
    for (int n : data) std::cout << n << " "; // 6 6 8 8 7
    return 0;
}

2. Функторы и std::function

Функторы — это объекты классов, которые перегружают оператор operator(). Они могут хранить состояние и вести себя как функции. std::function — это полиморфная обёртка для хранения любых вызываемых объектов.

Пример функтора

#include <iostream>

class Adder {
private:
    int base;
public:
    Adder(int b) : base(b) {}
    int operator()(int x) const { return base + x; }
};

int main() {
    Adder add5(5);
    std::cout << add5(10) << "\n"; // 15
    std::cout << add5(20) << "\n"; // 25
    return 0;
}

std::function: универсальная обёртка

#include <iostream>
#include <functional>
#include <vector>

void process(const std::vector<int>& data, std::function<bool(int)> predicate) {
    for (int x : data) {
        if (predicate(x)) std::cout << x << " ";
    }
    std::cout << "\n";
}

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6};
    
    // Можно передавать лямбды
    process(numbers, [](int n) { return n % 2 == 0; }); // 2 4 6
    process(numbers, [](int n) { return n > 3; });      // 4 5 6
    
    // И функторы
    struct GreaterThan {
        int limit;
        bool operator()(int n) const { return n > limit; }
    };
    process(numbers, GreaterThan{4}); // 5 6
    return 0;
}

3. Алгоритмы STL в функциональном стиле

Библиотека STL предоставляет множество алгоритмов, которые идеально сочетаются с лямбдами и функторами. Вместо циклов используйте std::transform, std::copy_if, std::accumulate и другие.

Map (трансформация) с std::transform

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> input = {1, 2, 3, 4, 5};
    std::vector<int> output(input.size());
    
    // Удвоение каждого элемента
    std::transform(input.begin(), input.end(), output.begin(),
                   [](int x) { return x * 2; });
    
    for (int n : output) std::cout << n << " "; // 2 4 6 8 10
    return 0;
}

Filter (фильтрация) с std::copy_if

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8};
    std::vector<int> even;
    
    // Оставляем только чётные числа
    std::copy_if(data.begin(), data.end(), std::back_inserter(even),
                 [](int x) { return x % 2 == 0; });
    
    for (int n : even) std::cout << n << " "; // 2 4 6 8
    return 0;
}

Reduce (свёртка) с std::accumulate

#include <iostream>
#include <vector>
#include <numeric> // для accumulate

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    
    // Сумма
    int sum = std::accumulate(numbers.begin(), numbers.end(),                

Блоги

Рекомендаций по книгам