البرمجة الوظيفية في C++: من الألف إلى الياء — دليل عملي

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

البرمجة الوظيفية في C++: من الألف إلى الياء



كثير من المطورين الذين يعرفون Python أو JavaScript اعتادوا على الأدوات القوية للبرمجة الوظيفية: لامدا، map، filter، reduce. لكن هل تعلم أن C++ توفر إمكانيات لا تقل مرونة للأسلوب الوظيفي؟ في هذه المقالة سنشرح البرمجة الوظيفية في C++ من المفاهيم الأساسية إلى التقنيات المتقدمة. ستتعلم كيفية كتابة كود أكثر إيجازًا وأمانًا وتعبيرًا باستخدام إمكانيات C++11/14/17 الحديثة.



1. أساسيات المنهج الوظيفي: تعبيرات لامدا و std::function



تبدأ البرمجة الوظيفية في C++ بتعبيرات لامدا. فهي تسمح بإنشاء دوال مجهولة مباشرة في نقطة الاستخدام. بناء جملة لامدا بسيط:



// لامدا أساسيةauto sum = [](int a, int b) -> int { return a + b; };std::cout << sum(5, 3); // 8

// لامدا مع التقاط المتغيراتint multiplier = 3;auto multiply = [multiplier](int x) { return x * multiplier; };std::cout << multiply(7); // 21


الميزة الرئيسية للامدا هي التقاط السياق. يمكنك التقاط المتغيرات بالقيمة ([=])، أو بالمرجع ([&])، أو بطريقة مختلطة. هذا هو أساس الإغلاقات التي تشكل حجر الزاوية للأسلوب الوظيفي.



لتخزين وتمرير لامدا، يُستخدم std::function — وهو غلاف متعدد الأشكال للكائنات القابلة للاستدعاء:



#include <functional>

std::function<int(int, int)> operation;

operation = [](int a, int b) { return a + b; };std::cout << operation(10, 20); // 30

operation = [](int a, int b) { return a * b; };std::cout << operation(10, 20); // 200


نصيحة: استخدم auto للامدا إذا لم تكن بحاجة لتخزينها كنوع. std::function يضيف تكاليف إضافية صغيرة، لذا يُفضل استخدامه فقط عند الحاجة لتعدد الأشكال.



2. خوارزميات STL: map، filter، reduce بأيدينا



في C++ لا توجد دوال مدمجة map، filter، reduce كما في Python، لكن STL توفر خوارزميات قوية تحل محلها. دعنا نستعرض الأساسيات:



2.1. Map — تحويل العناصر

بدلاً من map استخدم std::transform:



#include <algorithm>#include <vector>

std::vector<int> numbers = {1, 2, 3, 4, 5};std::vector<int> squares(numbers.size());

std::transform(numbers.begin(), numbers.end(), squares.begin(), [](int n) { return n * n; });// squares: {1, 4, 9, 16, 25}


2.2. Filter — التصفية حسب الشرط

نظير filter هو std::copy_if أو std::remove_if (مع الحذف اللاحق):



std::vector<int> numbers = {1, 2, 3, 4, 5, 6};std::vector<int> evens;

std::copy_if(numbers.begin(), numbers.end(), std::back_inserter(evens), [](int n) { return n % 2 == 0; });// evens: {2, 4, 6}


2.3. Reduce — طي المجموعة

لـ reduce استخدم std::accumulate من <numeric>:



#include <numeric>

std::vector<int> numbers = {1, 2, 3, 4, 5};int sum = std::accumulate(numbers.begin(), numbers.end(), 0, [](int acc, int n) { return acc + n; });// sum = 15


مثال متقدم: دمج map و filter و reduce لمعالجة البيانات:



std::vector<std::string> names = {"Alice", "Bob", "Charlie", "David"};// الحصول على مجموع أطوال الأسماء التي تبدأ بـ 'A' أو 'C'int result = std::accumulate(names.begin(), names.end(), 0,    [](int acc, const std::string& name) {        if (name[0] == 'A' || name[0] == 'C') {            return acc + name.length();        }        return acc;                

المدونات

توصيات الكتب