Wednesday, October 30, 2024

Signals and Slots in C++ using Boost's Library...

 I remember in the early part of my Bangalore stay, two C++ libraries attracted me - Boost and Loki. However, with the daily grinding in the office, i never got time to deep dive into it. And finally i got a chance to look into the Boost library in 2007, during my stay in Japan. But it was difficult - without a proper hand holding. I just got a chance to delve into the Boost pointers. 

Today, i will discuss about another important aspect of Boost library - Signals and Slots. These are Boost's answer to publisher-subscriber or Observer pattern or as the Java people call it - the event listener pattern - and for all others - simply the event driven programming.

You should use this pattern in case of...

Event-Driven Programming:

Signals and slots are ideal for event-driven programming, where objects need to react to events triggered by other objects.

GUI Development:

Boost.Signals2 is commonly used in GUI development to connect UI elements to actions or events.

Decoupling Components:

Signals and slots allow you to decouple components of your application, making it easier to modify and maintain the code.

Example : 

The following example writes "Hello, World!" using signals and slots. 

Here are the two function objects.

class Hello

{

public:

void operator()() const

{

cout << "Hello";

}

};


class World

{

public:

void operator()() const

{

cout << ", World!" << endl;

}

};

Then, we create a signal sig1, a signal that takes no arguments and has a void return value. 

boost::signals2::signal<void()> sig1;

Next, we connect the hello and world function objects to the signal using the connect method.

boost::signals2::connection c1 = sig1.connect(hello);


boost::signals2::connection c2 = sig1.connect(world);


By default, slots are pushed onto the back of the slot

list, so the output of this program will be as expected.


Hello, World!


The way signals and slots are connected, they can

be disconnected as wellas we have done here.


c1.disconnect(); // Disconnect the Hello object


Signals can propagate arguments to each of the slots

they call. For instance, a signal that propagates mouse

motion events might want to pass along the new mouse

coordinates and whether the mouse buttons are pressed.


//Slot Arguments

void print_args(float x, float y)

{

cout << "The arguments are " << x << " and " << y << endl;

}


void print_sum(float x, float y)

{

cout << "The sum is " << x + y << endl;

}


void print_product(float x, float y)

{

cout << "The product is " << x * y << endl;

}


void print_difference(float x, float y)

{

cout << "The difference is " << x - y << endl;

}


void print_quotient(float x, float y)

{

cout << "The quotient is " << x / y << endl;

}


And this is how we create the signals


boost::signals2::signal<void (float, float)> sig;


sig.connect(&print_args);

sig.connect(&print_sum);

sig.connect(&print_product);

sig.connect(&print_difference);

sig.connect(&print_quotient);


sig(5., 3.);


And the output will be as follows:


The arguments are 5 and 3 The sum is 8 The product is 15 The difference is 2 The quotient is 1.66667


Here is the complete source code of my

exploration.


Enjoy...


//============================================================================

// Name : BoostSignal2Test.cpp

// Author : Som

// Version :

// Copyright : som-itsolutions

// Description : Hello World in C++, Ansi-style

//============================================================================


#include <boost/signals2/signal.hpp>

#include <iostream>

using namespace std;

class Hello

{

public:

void operator()() const

{

cout << "Hello";

}

};


class World

{

public:

void operator()() const

{

cout << ", World!" << endl;

}

};

//Slot Arguments

void print_args(float x, float y)

{

cout << "The arguments are " << x << " and " << y << endl;

}


void print_sum(float x, float y)

{

cout << "The sum is " << x + y << endl;

}


void print_product(float x, float y)

{

cout << "The product is " << x * y << endl;

}


void print_difference(float x, float y)

{

cout << "The difference is " << x - y << endl;

}


void print_quotient(float x, float y)

{

cout << "The quotient is " << x / y << endl;

}



int main() {

boost::signals2::signal<void()> sig1;


Hello hello;

World world;


boost::signals2::connection c1 = sig1.connect(hello);

boost::signals2::connection c2 = sig1.connect(world);


sig1();


    c1.disconnect(); // Disconnect the HelloWorld object

    cout << "c1 is disconnected\n";


    sig1();


    c2.disconnect();

    cout << "c2 is disconnected\n";

    sig1();



    //parameter passing


    boost::signals2::signal<void (float, float)> sig;


    sig.connect(&print_args);

    sig.connect(&print_sum);

    sig.connect(&print_product);

    sig.connect(&print_difference);

    sig.connect(&print_quotient);


    sig(5., 3.);


return 0;

}


No comments: