Более естественный стимул :: связать альтернативу? - PullRequest
3 голосов
/ 01 февраля 2009

Не поймите меня неправильно: * Boost's bind() отлично.

Но я очень не хочу писать и читать с ним код, и я потерял надежду, что мои коллеги когда-нибудь будут его использовать / использовать.

Я получаю такой код:

btn.clicked.connect(bind(&BetBar::placeBet, this, bet_id));
animator.eachFrame.connect(bind(&Widget::move, buttons[bet_id]));

Что, хотя и логично, очень далеко от того, что я бы назвал хорошим кодом.

Для демонстрации ... в C ++ 1x у нас будет это:

btn.clicked.connect([&](int bet_id){ placeBet(bet_id); })
animator.eachFrame.connect([&](Point newPos) { buttons[bet_id].move(newPos) })

И хороший DSL может выглядеть примерно так:

on(btn.clicked) placeBet(bet_id);
on(animator.eachFrame) buttons[bet_id].move(eachFrame::newPos);

Как вы справляетесь с привязкой в ​​C ++? Вы просто живете с тем, что дает вам импульс?

Ответы [ 3 ]

3 голосов
/ 02 февраля 2009

Кажется, вы хотите следующее:

  • Неявное связывание с this
  • Альтернатива для круглых скобок, связанных с вызовом функции, которая хранит привязку.
  • Автоматическая идентификация, какие параметры в вашем лямбда-выражении связаны.

Первое очень сложно в C ++ сегодня, поскольку this неявно присутствует в очень немногих контекстах, и вы, конечно, не можете передать его неявно функциям. То есть Вы не можете достичь этого с помощью библиотечной функции, но вы можете с помощью макроса. Тем не менее, это было бы ужасно.

Вторая часть намного проще:

button.clicked.handler = bind(BetBar::placeBet, this, bet_id);

Это просто требует handler.operator=(boost::function<void(*)()> const&)

Третий вопрос снова сложен, потому что вы только что разработали еще один случай двухфазного поиска имени. Это было достаточно сложно с шаблонами. Трюк Boost _1 работает, делая ясным, какие аргументы должны быть связаны позже. Тем не менее, _1 как имя не волшебство. Это в основном бесплатная функция, возвращающая boost :: arg <1>. Таким образом, с подходящим определением animator.eachFrame.newPos следующее можно сделать эквивалентным:

animator.eachFrame.handler = bind(&Widget::move, buttons[bet_id], _1)
animator.eachFrame.handler = bind(&Widget::move, buttons[bet_id], animator.eachFrame.newPos)
2 голосов
/ 01 февраля 2009

Я сомневаюсь, что вы можете стать лучше, чем это на pre-0x C ++. Boost.Lambda или Phoenix предоставляют свои собственные механизмы привязки, но в таких случаях они не станут более читабельными, на самом деле.

Если бы вы могли подумать о том, как запрограммировать такой DSL в текущем C ++, используя boost :: proto (есть ли другие альтернативы?), Тогда вы можете получить лучшую помощь только от других прото-ребят из boost. сам список рассылки, так как это было бы над моей головой.

Для сотрудников: Когда они профессионально занимаются программированием на С ++ (читай: им платят за это), они либо за это ухмыляются, либо должны выполнять другую работу. Если они не смогут прочитать такие простые конструкции, они, вероятно, вызовут большую нагрузку на обслуживание, чем когда-либо, помогая реализовать новые функции.

В таком случае предоставьте хорошую привязку к Lua (или любому другому языку сценариев, который вы предпочитаете) и заставьте их выполнять бизнес-логику на этом языке. Во всяком случае, это на самом деле неплохое решение.

0 голосов
/ 02 февраля 2009

Как примечание: на самом деле хороший DSL может выглядеть примерно так:

btn.clicked { |bet_id| placeBet bet_id }
animator.eachFrame { |newPos| buttons[bet_id].move newPos }

Чтобы ответить на ваш вопрос: Для простого примера, который вы предоставили, просто bind отлично работает.

...