البرمجة التفاعلية في C++: مكتبات RxCpp و Boost.Signals2

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

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

ابدأ الدورة

البرمجة التفاعلية في C++: نظرة عامة على مكتبات RxCpp و Boost.Signals2



البرمجة التفاعلية (Reactive Programming) هي نموذج يركز على تدفقات البيانات غير المتزامنة ونشر التغييرات. في لغة C++، يتم تنفيذ هذا النموذج من خلال مكتبات تسمح بمعالجة الأحداث والإشارات والتسلسلات غير المتزامنة للبيانات بطريقة تعريفية. في هذه المقالة، سنستعرض مكتبتين رئيسيتين للبرمجة التفاعلية في C++: RxCpp (Reactive Extensions for C++) و Boost.Signals2. كلتا المكتبتين تحلان مشكلة معالجة الأحداث، ولكن بدرجات متفاوتة من التعقيد والوظائف.



لماذا نحتاج البرمجة التفاعلية في C++؟



غالبًا ما يكون الكود التقليدي الحتمي معقدًا عند التعامل مع الأحداث غير المتزامنة، أو إدخال المستخدم، أو طلبات الشبكة، أو تعدد المهام. تقدم البرمجة التفاعلية ما يلي:



  • النهج التعريفي: تصف "ماذا" يجب أن يحدث، وليس "كيف".
  • تكوين التدفقات: سهولة دمج وتصفية وتحويل تدفقات البيانات.
  • إدارة تعدد المهام: آليات مدمجة لتبديل السياقات والمزامنة.
  • معالجة الأخطاء: خط أنابيب موحد للبيانات والاستثناءات.


مكتبة RxCpp



RxCpp هي نسخة من الامتدادات التفاعلية (Rx) للغة C++. توفر مجموعة قوية من العوامل (operators) للعمل مع التسلسلات غير المتزامنة للبيانات. المفاهيم الأساسية: observable (مصدر البيانات) و observer (المشترك).



التثبيت

RxCpp هي مكتبة header-only. يكفي استنساخ المستودع وتضمين ملفات الرأس:

#include <rxcpp/rx.hpp>using namespace rxcpp;using namespace rxcpp::sources;using namespace rxcpp::operators;


مثال 1: اشتراك بسيط في تدفق الأرقام

لننشئ observable يقوم بتوليد الأرقام من 1 إلى 5، ونشترك فيه:

#include <iostream>#include <rxcpp/rx.hpp>

int main() { auto values = range(1, 5); // observable: 1,2,3,4,5

values. subscribe([](int v) { std::cout << "تم الاستلام: " << v << std::endl; }, []() { std::cout << "اكتمل التدفق" << std::endl; });

return 0;}


مثال 2: التصفية والتحويل

تسمح العوامل التفاعلية بمعالجة البيانات بسهولة. لنقم بتصفية الأرقام الزوجية وضربها في 10:

auto values = range(1, 10);

values .filter([](int v) { return v % 2 == 0; }) // الأرقام الزوجية فقط .map([](int v) { return v * 10; }) // نضرب في 10 .subscribe([](int v) { std::cout << "النتيجة: " << v << std::endl; });// الإخراج: 20, 40, 60, 80, 100


مثال 3: دمج التدفقات

لنقم بدمج تدفقين باستخدام العامل merge:

auto stream1 = interval(std::chrono::milliseconds(100)).take(3);auto stream2 = interval(std::chrono::milliseconds(150)).take(3);

stream1.merge(stream2) .subscribe([](long v) { std::cout << v << " "; });// الإخراج المحتمل: 0 0 1 2 1 2 (قد يختلف الترتيب)


مكتبة Boost.Signals2



Boost.Signals2 هي مكتبة لتنفيذ الإشارات والفتحات (signals & slots). وهي جزء من مكتبات Boost وتوفر آلية آمنة من حيث النوع لاستدعاءات الإرجاع. على عكس RxCpp، فإن Signals2 ليست مصممة للعمل مع تدفقات البيانات، بل لمعالجة الأحداث المنفصلة.



المفاهيم الأساسية

  • الإشارة (signal): كائن يمكن "استدعاؤه" وسيقوم بإخطار جميع المشتركين فيه.
  • الفتحة (slot): دالة أو كائن دالي (functor) يتم ربطه بإشارة.

توصيات