I want to send a signal to each subclass of a class. To achieve this I am using the signals2 library from boost. Because of the usage of the code I need to use a CRTP.
Minimal example, which is included in a header file:
class A {
static boost::signals2::signal<void()>& getSignal() {
static boost::signals2::signal<void()> signal;
return signal;
}
public:
static void sendSignal() {
getSignal()();
}
protected:
template <typename slot_t>
static boost::signals2::connection addSlot(slot_t slot) {
return _entityToBeDeleted().connect(slot);
}
};
template <typename concrete_B>
class B : A {
static boost::signals2::connection _installHandler() {
return A::addSlot([]() {
//Do something
});
}
static const boost::signals2::connection connection;
};
template<typename concrete_B>
const boost::signals2::connection B<concrete_B>::connection = _installHandler();
class C : public B<C> {
//Concrete subclass
};
Some client class, that wants to notify the subclasses makes a call to A::sendSignal
, which invokes all slots connected to the signal. What exactly the content of this notification is is irrelevant for the purpose of this question. As you can see, the side effect of the static initializer of B<concrete_B>::connection
is needed for this to work, but as the object itself is never used (nor needed) the complete initialization is skipped.
The problem is: The call to _installHandler() is completely optimized away by the compiler (I'm using MSVC with Visual Studio 2017). I verified this by writing an additional test case, which explicitly tests if the connection object is valid. When I used the object this way the code worked and all other test cases passed. When I removed the additional test case the others failed again.
I tried declaring the static variable volatile as suggested in an answer to this question, but it did not help.
How do I prevent the initialization of the the static connection object to be optimized away. Or: How do I ensure a function with sideeffects that is created by template instanciation is always called once at the beginning of the executable, even though the returned object is never actually used; ideally during static initialization.
I thought about using the connection somehow in another static initializer of this class (std::cout << connection.connected() << '\n';
or something like this) that is already safe to be called (because the object this initializes is definitely used), but this seems like a nasty hack.
Edit: I implemented the "hack" and it works flawlessly, nontheless I am interested if there is a way to implement the desired behaviour in a "cleaner" way.