Reputation:
Don't get me wrong: Boost's bind()
is great.
But I do hate to write&read code with it, and I've given up hope my coworkers will ever grok/use it.
I end up with code like this:
btn.clicked.connect(bind(&BetBar::placeBet, this, bet_id));
animator.eachFrame.connect(bind(&Widget::move, buttons[bet_id]));
Which, while logical, is very far from what I'd call nice code.
To demonstrate... in C++1x we'll have this:
btn.clicked.connect([&](int bet_id){ placeBet(bet_id); })
animator.eachFrame.connect([&](Point newPos) { buttons[bet_id].move(newPos) })
And a good DSL could look kinda like this:
on(btn.clicked) placeBet(bet_id);
on(animator.eachFrame) buttons[bet_id].move(eachFrame::newPos);
How do you cope with binding in C++? Do you just live with what boost gives you?
Upvotes: 3
Views: 1784
Reputation: 179779
It seems you want the following:
this
The first is very hard in C++ today, as this
is implicit in very few contexts, and you certainly cannot pass it to functions implicitly. I.e. you can't achieve this with a library function, but you could with a macro. Still, it would be ugly.
The second part is far easier:
button.clicked.handler = bind(BetBar::placeBet, this, bet_id);
This just requires handler.operator=(boost::function<void(*)()> const&)
The third is hard again, because you have just designed another case of two-phase name lookup. That was hard enough with templates. boost's _1 trick works by making it explicit which arguments should be bound later. However, _1 as name isn't magic. It's basically a free function returning boost::arg<1>. So, with a suitable definition of animator.eachFrame.newPos the following could be made equivalent:
animator.eachFrame.handler = bind(&Widget::move, buttons[bet_id], _1)
animator.eachFrame.handler = bind(&Widget::move, buttons[bet_id], animator.eachFrame.newPos)
Upvotes: 3
Reputation: 414139
As a side note, actually a good DSL could look kinda like this:
btn.clicked { |bet_id| placeBet bet_id }
animator.eachFrame { |newPos| buttons[bet_id].move newPos }
To answer your question: For the simple example you provided a plain bind
works just fine.
Upvotes: 0
Reputation: 4511
I doubt you can get any better then this on pre-0x C++. Boost.Lambda or Phoenix provide their own binding mechanisms, but for such cases it won't get any more readable, really.
If you could think of how to program such a DSL within the current C++ using boost::proto (are there any other alternatives?), well, then you may get better help by the only other proto-guys on the boost mailing list itself, as this would be over my head.
For the co-workers: When they are doing programming C++ professionally (read: they get paid for it), they either grok it, or they should do another job. If they can't read such simple constructs, they will probably produce a bigger maintenance burden then they can ever make up with helping on implementing new features.
In such a case, providing a nice binding to Lua (or whatever scripting language you prefer), and make them do the business logic in that language. This is actually a not too bad solution, anyway.
Upvotes: 2