Programação Reativa em C++: uma abordagem moderna para tratamento de eventos
Programação Reativa (Reactive Programming) é um paradigma orientado a fluxos de dados assíncronos e propagação de mudanças. Em C++, este conceito permite construir aplicações flexíveis, responsivas e de fácil manutenção, especialmente nas áreas de GUI, comunicação em rede e processamento de sinais. Ao contrário da abordagem imperativa tradicional, onde você especifica explicitamente uma sequência de ações, a programação reativa descreve dependências entre dados: quando um elemento muda, todos os que dependem dele são atualizados automaticamente.
Conceitos principais da programação reativa
- Observable (Observável) — fonte de dados que gera eventos.
- Observer (Observador) — assinante que reage aos eventos.
- Subscription (Assinatura) — conexão entre Observable e Observer.
- Operadores — funções para transformar, filtrar e combinar fluxos (map, filter, merge, switch_on_next).
Em C++, a programação reativa é implementada através de bibliotecas que fornecem essas abstrações. Vamos considerar três ferramentas mais populares.
1. RxCpp — biblioteca Reactive Extensions para C++
RxCpp é uma adaptação do popular modelo ReactiveX (Rx) para C++. Ela fornece um poderoso conjunto de operadores para trabalhar com fluxos assíncronos. A biblioteca utiliza C++17/20 moderno, templates e expressões lambda.
Exemplo: assinatura simples em um fluxo de números
#include <rxcpp/rx.hpp>#include <iostream>
int main() { // Cria um fluxo observável de números auto observable = rxcpp::observable<>::range(1, 5);
// Assina observable.subscribe( [](int v) { std::cout << "Recebido: " << v << std::endl; }, // on_next []() { std::cout << "Concluído!" << std::endl; } // on_completed );
return 0;}Exemplo: filtragem e transformação
#include <rxcpp/rx.hpp>#include <iostream>
int main() { auto values = rxcpp::observable<>::range(1, 10) .filter([](int x) { return x % 2 == 0; }) // apenas pares .map([](int x) { return x * x; }); // eleva ao quadrado
values.subscribe([](int v) { std::cout << v << " "; }); // Saída: 4 16 36 64 100
return 0;}Características do RxCpp:
- Suporte a multithreading e agendadores (schedulers).
- Conjunto rico de operadores (merge, zip, combine_latest, debounce, throttle).
- Integração com std::future e operações assíncronas.
- Compatibilidade com CMake e vcpkg.
2. Boost.Signals2 — sinais e slots sem dependências externas
Boost.Signals2 é uma biblioteca do conjunto Boost que implementa o mecanismo de sinais e slots. Ela é uma evolução thread-safe da biblioteca original Boost.Signals. Ideal para arquiteturas orientadas a eventos, especialmente em GUI e motores de jogos.
Exemplo: sinal simples com dois slots
#include <boost/signals2.hpp>#include <iostream>
void hello() { std::cout << "Olá, "; }void world() { std::cout << "mundo!" << std::endl; }
int main() { boost::signals2::signal<void()> sig;
sig.connect(&hello); sig.connect(&world);
sig(); // Chamada do sinal — chamará ambos os slots // Saída: Olá, mundo!
return 0;}Exemplo: sinal com parâmetros e valor de retorno
#include <boost/signals2.hpp>#include <iostream>#include <string>