一个更自然的boost::bind替代方案?

3

不要误解:Boost的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++中的绑定?你只是接受boost提供的一切吗?
3个回答

3
似乎您需要以下内容:
  • 隐式绑定到this
  • 一个与函数调用相关的括号的替代,它存储了绑定。
  • 自动识别lambda表达式中哪些参数已绑定。

对于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

我怀疑你在 pre-0x C++ 中找不到比这更好的了。Boost.Lambda 或 Phoenix 提供了自己的绑定机制,但对于这种情况来说,它实际上不会更易读。

如果你能想出如何使用 boost::proto 在当前的 C++ 中编写 DSL(还有其他替代方案吗?),那么你可能需要在 boost 邮件列表中寻求 proto-guys 的帮助,因为这已经超出了我的能力范围。

对于同事们:当他们以专业方式(即:得到报酬)进行 C++ 编程时,他们要么理解它,要么就该另谋职业。如果他们无法阅读这样简单的结构,他们可能会产生比实现新功能所能弥补的更大的维护负担。

在这种情况下,提供一个漂亮的绑定到 Lua(或您喜欢的任何脚本语言),并让他们在该语言中处理业务逻辑。这实际上是一个不错的解决方案。


proto看起来令人惊叹,我一定会深入研究它。谢谢! - Iraimbilanja

0

顺便提一下,一个好的领域特定语言(DSL)可能看起来像这样:

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

回答你的问题:对于你提供的简单示例,一个普通的bind就可以很好地工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接