Reputation: 21
In my private project I use boost::signals2 to send messages from several classes to a common receiver. My Question is: how can I send messages from the constructor of a class? The problem is, that the signal in this case does not exist until an object of class A is instantiated (until the constructor is executed). But at this point there was not yet a chance for some other code to establish a slot.
I tried to use static boost::signals2::signal<void(const std::string & Msg)> but then I get loader errors 'undefined reference to class::signal'.
Below is a very stripped down version of my code for illustration purposes. The question is: how can class B receive a message from the constructor of class A? Or with other words: how can I connect a slot to the signal of class A before the constructor of class A is executed?
class A {
public:
/*static*/ boost::signals2::signal<void(const std::string & Msg)> sigA;
A() { sigA("message from constructor A"); }
};
class B {
B() {
A a;
a.sigA.connect([](const std::string & msg) { std::cerr << msg << '\n'; } );
}
};
For your information: I use fedora 33, gcc 11.2.1 and C++17.
Please excuse my english: it's not my native language und i am missing some experience...
Upvotes: 1
Views: 275
Reputation: 21
Meanwhile I found a solution for my problem by myself. Below is a fully working example of how the constructor of class A fires a signal that itself is a (static) member of class A:
#include <string>
#include <iostream>
#include <functional>
#include <boost/signals2/signal.hpp>
class A {
public:
using Signal = boost::signals2::signal<void(const std::string & Msg)>;
static Signal sigA;
A() { sigA("message from constructor A"); }
};
A::Signal A::sigA;
class B {
public:
B() {}
void disp(const std::string & msg) { std::cout << msg << '\n'; }
};
int main()
{
B b; // slot b.disp() now exists
auto slot = std::bind(&B::disp, b, std::placeholders::_1);
A::sigA.connect(slot); // subscribe slot b.disp() to A::sigA
A a; // constructor of class A fires signal sigA, b.disp() writes to cout
};
Upvotes: 1
Reputation: 4595
Technically, you could pass the slot to class A
constructor.
class A {
public:
A(boost::signals2::slot<void(const std::string &)> slot) {
sigA.connect(slot);
sigA("message from constructor A"); }
};
class B {
B() {
A a([](const std::string & msg) { std::cerr << msg << '\n'; });
}
};
Note that the semantics are a bit weird. For once, there is no way to obtain the connection
object. you could use an out parameter on the constructor, but that really is a code smell.
Generally, constructors are used to initialize the object, not to perform logic that might affect objects that are not class members.
I would strongly suggest subscribing the slot in a separate method.
Upvotes: 1