Public boost::signal object

939 views Asked by At

I make my boost::signals public because I'm lazy.

class Button {
public:
    signal<void()> clicked;
};

int main() {
    Button btn;
    btn.clicked.connect(handleClick);
}

... rather than encapsulating with a Button::OnClicked(boost::function<void()>).

Is this going to come back and bite me?

4

There are 4 answers

1
user21714 On BEST ANSWER

It depends.

It has bitten me before when I wanted to add some special logic each time an object connected to another object's signals. This is the most likely case to bite you.

Also, it can make it difficult to keep track of exactly when other objects are connecting to any given object.

I would say hide the connections behind a function to be on the safe side.

I usually use a macro to do the vanilla function definition.

#define SIGNAL(slot,name) connection name(function<slot> func) { return _##name##.connect(func);}

And then in a class definition:

SIGNAL(void(),clicked)

This assumes you follow the convention of naming the signal '_clicked' but you can substitute any convention. It generally keeps the interface cleaner for all of your classes. When you want to add special connection logic you can, without changing all of the other objects that use the signal.

EDIT

One instance was when the signal object was actually moved to a delegate implementation inside another class, but it still made sense for objects to connect through the original class. This broke all of the places that tried to connect to it. If they had been using function accessors to connect, it would have been as simple as changing the function to look up the signal in the delegate. But as it was it broke all the users of the original class.

Or, when I wanted to log each time something connected to a specific signal. This was just for debugging purposes, but it can be very helpful if you suspect something wonky is going on like cycles in your signal connections.

0
timpatt On

I've stumbled across a good reason not to do this.

We are looking at using a third party library that exposes boost::signals on an external interface. This library depends on a version of boost with a set of compiler definitions that are binary-incompatible with the standard Visual Studio compiler definitions that we use in our project. Whenever we attempt to call the third-party-library's signal.connect, things die.

The solution for us is either to:

  1. Recompile all of our source and dependent libraries with the boost version provided by them.
  2. Wrap the boost signals and hide the implementation

Something to consider, at least!

0
MattyT On

Well, this questions really has nothing to do with boost::signal or function - it's all about encapsulation.

Do client's of the Button class need complete access to clicked? If all they ought to be able to do is subscribe to it then allow only that with the OnClicked method. Exposing more than that is likely to bite you IMHO.

As always you balance costs vs benefits. In this case the cost is very low. If you were on my team I'd strongly recommend you add the OnClicked method.

0
StackedCrooked On

I set them public as well and use upper-camel-case for its object name. This approach never backfired on me.