7 ms·
For a more modern form of this, take a look at Boost.Signals2. https://www.boost.org/doc/libs/1_68_0/doc/html/signals2.html https://www.boost.org/doc/libs/1_68
by kenrose 8y ago
For a more modern form of this, take a look at Boost.Signals2.
https://www.boost.org/doc/libs/1_68_0/doc/html/signals2.html https://www.boost.org/doc/libs/1_68_0/doc/html/signals2.html
It provides a slightly nicer interface in that signals can be defined in a single template argument, vs. splitting args / return type as separate template arguments. For example:
boost::signals2::signal<void (float, float)> sig;
would allow the following function as a slots:
void do_something(float x, float y) { ... }
There's also Qt's signal/slots implementation:
http://doc.qt.io/archives/qt-4.8/signalsandslots.html http://doc.qt.io/archives/qt-4.8/signalsandslots.html
Qt's approach requires a separate compilation pass woith a Qt-specific tool named "moc" which declares a bunch of info in the signal class that's necessary for the slot implementation.
IMO, the Boost implementation is nicer. It's vanilla C++ (no moc required), is thread safe, and supports some advanced features like "combiners".
- seandhi 8y agoI am asking because I am relearning C++, but would it preferable to use Boost for callbacks over using lambdas, assuming you’re on a recent version?
- RcouF1uZ4gsC 8y agoYou can actually use both. You can use a lambda to provide the callable for the Boost signal.
- kenrose 8y agoGood point about lambdas. I haven't done much C++ since about 2011, which is when lambdas were added to the standard. In terms of which to use, it depends on your use case. Lambdas let you easily specify a single callback function, so they're a nice syntactic sugar for passing to STL functions (e.g., for_each). If you're the sender and only have one callback to fire, a lambda is great for this. If you have to fire n callbacks, you could probably build a signal / slot mechanism with lambdas. But at that point, I'd start to consider using a dedicated library like signals2. It takes care of a bunch of things like object lifetime (e.g., slot deallocation if an object is destructed), efficient management of the list of slots, and thread safety.
- notatcomputer68 8y agoI would use std::function and lambdas.
- jcelerier 8y ago> but would it preferable to use Boost for callbacks over using lambdas, assuming you’re on a recent version? it's not comparable, a boost::signal is equivalent to a list of functions which gets called when the signal is triggered, instead of a single function.
- slavik81 8y agoQt 4 hit end-of-life in 2015. These are the Qt 5 docs: http://doc.qt.io/qt-5/signalsandslots.html http://doc.qt.io/qt-5/signalsandslots.html
- jcelerier 8y ago> Qt's approach requires a separate compilation pass woith a Qt-specific tool named "moc" which declares a bunch of info in the signal class that's necessary for the slot implementation. If you are willing to accept uglier macros, you can have QObject-compatible signals / slots in pure C++ without any kind of specific tool : https://github.com/woboq/verdigris https://github.com/woboq/verdigris Also, Qt's approach is thread-safe (if you call a signal in a thread A on an object attached to a thread B, the slot will be executed in thread B) since it is tied to Qt's event loop.
- grefab 8y agoWe successfully use verdigris in production (image processing application with QT/QML as GUI). This allowed using bazel without having to teach it moc.
- vvanders 8y agoI actually prefer QT's approach, it allows you to annotate with extra properties if you want. Back in games we'd usually use some DSL to generate all the boilerplate code for things like this(also including a whole bunch of editor-specific flags for signals/members). Also, every time I bring in boost headers I watch compile times crater. C++ 11 or 14 is good enough at this point that I don't see a strong reason to use boost. I know of 2-3 projects that migrated from boost -> C++11 for that reason alone.
- klodolph 8y agoI’ve seen a lot of libraries, including parts of Boost, advertised as header-only. To me, this reflects the sad state of building cross-platform C++ dependencies; headers are the only things that library developers are confident that their users will be happy with. I’m very comfortable with doing build system maintenance, so the header-only “feature” seems like a straight-up drawback to me, killing my productivity with longer compile times.
- geezerjay 8y ago> To me, this reflects the sad state of building cross-platform C++ dependencies; headers are the only things that library developers are confident that their users will be happy with. ...or that the code uses templates extensively (it's boost after all) thus everything must be placed in the same compilation unit so that the code can be generated at compile time.
- josefx 8y agoEven with templates you could split of declaration and implementation. That would help with reducing compile times at the cost of having the user explicitly instantiate the used variations in some central location.
- geezerjay 8y ago> Even with templates you could split of declaration and implementation. No, you can't. The only case where the declaration of template functions/classes can be separated from definitions is in the rare cases where only a fixed and predetermined set of objects/values are used, thus enabling explicit instantiation.
- deleted 8y ago[deleted]
- quietbritishjim 8y agoBoost signals also handles multiple (or zero) callbacks associated with a single signal. I'm not sure but I believe it also allows calling the slot at a later point from a message pump – certainly Qt's signals and slots do. A more direct analogue of the type discussed in the article is std::function, which is simply a type that can contain any one callable (function pointer or function object, including lambda functions) or can be empty (like a null function pointer), and can be called in an immediate synchronous way.