Programação Reativa em C++: visão geral das bibliotecas RxCpp e Boost.Signals2
Programação Reativa (Reactive Programming) é um paradigma orientado a fluxos de dados assíncronos e propagação de mudanças. Em C++, este paradigma é implementado através de bibliotecas que permitem processar eventos, sinais e sequências assíncronas de dados de forma declarativa. Neste artigo, abordaremos duas bibliotecas-chave para programação reativa em C++: RxCpp (Reactive Extensions for C++) e Boost.Signals2. Ambas as bibliotecas resolvem a tarefa de processamento de eventos, mas com diferentes níveis de complexidade e funcionalidade.
Por que a programação reativa em C++?
O código imperativo tradicional frequentemente se torna complexo ao lidar com eventos assíncronos, entrada do usuário, requisições de rede ou multithreading. A programação reativa oferece:
- Abordagem declarativa: Você descreve "o que" deve acontecer, não "como".
- Composição de fluxos: Facilidade para combinar, filtrar e transformar fluxos de dados.
- Gerenciamento de multithreading: Mecanismos embutidos para alternância de contextos e sincronização.
- Tratamento de erros: Um pipeline unificado para dados e exceções.
Biblioteca RxCpp
RxCpp é uma adaptação das Reactive Extensions (Rx) para C++. Ela fornece um conjunto poderoso de operadores para trabalhar com sequências assíncronas de dados. Os conceitos principais são: observable (fonte de dados) e observer (assinante).
Instalação
RxCpp é uma biblioteca header-only. Basta clonar o repositório e incluir os arquivos de cabeçalho:
#include <rxcpp/rx.hpp>using namespace rxcpp;using namespace rxcpp::sources;using namespace rxcpp::operators;Exemplo 1: Assinatura simples em um fluxo de números
Vamos criar um observable que gera números de 1 a 5 e assinar nele:
#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 << "Recebido: " << v << std::endl; }, []() { std::cout << "Fluxo concluído" << std::endl; });
return 0;}Exemplo 2: Filtragem e transformação
Os operadores reativos permitem manipular dados facilmente. Vamos filtrar números pares e multiplicá-los por 10:
auto values = range(1, 10);
values .filter([](int v) { return v % 2 == 0; }) // apenas pares .map([](int v) { return v * 10; }) // multiplicar por 10 .subscribe([](int v) { std::cout << "Resultado: " << v << std::endl; });// Saída: 20, 40, 60, 80, 100Exemplo 3: Combinação de fluxos
Vamos combinar dois fluxos usando o operador 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 << " "; });// Saída possível: 0 0 1 2 1 2 (a ordem pode variar)Biblioteca Boost.Signals2
Boost.Signals2 é uma biblioteca para implementação de sinais e slots (signals & slots). Ela faz parte das bibliotecas Boost e fornece um mecanismo type-safe para callbacks. Ao contrário do RxCpp, Signals2 não é projetada para trabalhar com fluxos de dados, mas sim para processar eventos discretos.
Conceitos principais
- Sinal (signal): um objeto que pode ser "chamado" e notificará todos os seus assinantes.
- Slot (slot): uma função ou objeto funcional que é
Também na biblioteca
Geolocalização e Mapas em C# (.NET): Visão Geral de Bibliotecas e Ferramentas
Event Bus e padrão Observer em Swift: implementação e exemplos
Trabalhando com datas em Swift: Foundation e DateFormatter
tsyringe para TypeScript: guia completo com exemplos práticos