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

发布于 2024-07-12 12:54:25 字数 734 浏览 11 评论 0原文

不要误会我的意思: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++ 中的绑定? 你只是依靠给你带来的动力而生活吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夏花。依旧 2024-07-19 12:54:25

您似乎想要以下内容:

  • 隐式绑定到 this
  • 与存储绑定的函数调用关联的括号的替代方案。
  • 自动识别 lambda 表达式中的哪些参数已绑定。

第一个在当今的 C++ 中非常困难,因为 this 在极少数上下文中是隐式的,并且您当然不能将其隐式传递给函数。 即,您无法使用库函数来实现此目的,但可以使用宏来实现。 尽管如此,它仍然会很丑陋。

第二部分要容易得多:

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

这只需要 handler.operator=(boost::functionconst&)

第三部分又很难了,因为你刚刚设计了另一个两阶段名称查找的情况。 对于模板来说这已经够难的了。 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)

It seems you want the following:

  • Implicit binding to this
  • An alternative for the parentheses associated with the function call which stores the binding.
  • Automatic identification which parameters in your lambda-expression are bound.

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)
仄言 2024-07-19 12:54:25

我怀疑在 0x 之前的 C++ 上你能得到比这更好的东西。 Boost.Lambda 或 Phoenix 提供了自己的绑定机制,但对于这种情况,它实际上不会变得更具可读性。

如果您能想到如何使用 boost::proto 在当前的 C++ 中编写这样的 DSL(还有其他替代方案吗?),那么您可能会从 boost 邮件列表中唯一的其他原型人员那里得到更好的帮助,因为这超出了我的能力范围。

对于同事来说:当他们专业地进行 C++ 编程时(阅读:他们为此获得报酬),他们要么理解它,要么应该做另一份工作。 如果他们无法阅读如此简单的结构,他们可能会产生更大的维护负担,然后他们可以通过帮助实现新功能来弥补。

在这种情况下,为 Lua(或您喜欢的任何脚本语言)提供良好的绑定,并让它们用该语言执行业务逻辑。 无论如何,这实际上是一个不太糟糕的解决方案。

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.

水晶透心 2024-07-19 12:54:25

作为旁注,实际上一个好的 DSL 可能看起来有点像这样:

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

回答你的问题:对于这个简单的例子,你提供了一个简单的 bind 工作得很好。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文