Don't get me wrong: Boost's bind()
is great.
不要误会我的意思:Boost的bind()很棒。
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:
为了演示...在C ++ 1x中我们将有:
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:
一个好的DSL看起来有点像这样:
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?
你如何应对C ++中的绑定?你只是生活在提升给你的东西吗?
3 个解决方案
#1
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.
隐含绑定到此
与存储绑定的函数调用关联的括号的替代方法。
自动识别lambda表达式中的哪些参数被绑定。
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.
第一个在C ++中非常难,因为这在很少的上下文中是隐含的,你当然不能隐式地将它传递给函数。即你无法用库函数实现这一点,但你可以使用宏。不过,这将是丑陋的。
The second part is far easier:
第二部分要容易得多:
button.clicked.handler = bind(BetBar::placeBet, this, bet_id);
This just requires handler.operator=(boost::function<void(*)()> const&)
这只需要handler.operator =(boost :: function
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:
第三个是困难的,因为你刚刚设计了另一个两阶段名称查找案例。这对模板来说已经够难了。 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
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.
我怀疑你在0x C ++之前可以做得更好。 Boost.Lambda或Phoenix提供了他们自己的绑定机制,但对于这种情况,它实际上不会更具可读性。
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.
如果你能想到如何使用boost :: proto在当前的C ++中编程这样的DSL(还有其他选择吗?),那么你可以通过boost邮件列表本身的其他原始人获得更好的帮助,因为这将超过我的头脑。
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.
对于同事们来说:当他们专业地编写C ++编程时(阅读:他们为此付出代价),他们或者要么嘲笑它,要么他们应该做另一份工作。如果他们无法阅读这些简单的结构,他们可能会产生更大的维护负担,然后他们可以弥补实现新功能。
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.
在这种情况下,提供与Lua(或您喜欢的任何脚本语言)的良好绑定,并使它们使用该语言执行业务逻辑。无论如何,这实际上是一个不太糟糕的解决方案。
#3
As a side note, actually a good DSL could look kinda like this:
作为旁注,实际上一个好的DSL看起来有点像这样:
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.
回答你的问题:对于简单的例子,你提供了一个简单的绑定工作正常。
#1
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.
隐含绑定到此
与存储绑定的函数调用关联的括号的替代方法。
自动识别lambda表达式中的哪些参数被绑定。
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.
第一个在C ++中非常难,因为这在很少的上下文中是隐含的,你当然不能隐式地将它传递给函数。即你无法用库函数实现这一点,但你可以使用宏。不过,这将是丑陋的。
The second part is far easier:
第二部分要容易得多:
button.clicked.handler = bind(BetBar::placeBet, this, bet_id);
This just requires handler.operator=(boost::function<void(*)()> const&)
这只需要handler.operator =(boost :: function
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:
第三个是困难的,因为你刚刚设计了另一个两阶段名称查找案例。这对模板来说已经够难了。 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
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.
我怀疑你在0x C ++之前可以做得更好。 Boost.Lambda或Phoenix提供了他们自己的绑定机制,但对于这种情况,它实际上不会更具可读性。
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.
如果你能想到如何使用boost :: proto在当前的C ++中编程这样的DSL(还有其他选择吗?),那么你可以通过boost邮件列表本身的其他原始人获得更好的帮助,因为这将超过我的头脑。
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.
对于同事们来说:当他们专业地编写C ++编程时(阅读:他们为此付出代价),他们或者要么嘲笑它,要么他们应该做另一份工作。如果他们无法阅读这些简单的结构,他们可能会产生更大的维护负担,然后他们可以弥补实现新功能。
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.
在这种情况下,提供与Lua(或您喜欢的任何脚本语言)的良好绑定,并使它们使用该语言执行业务逻辑。无论如何,这实际上是一个不太糟糕的解决方案。
#3
As a side note, actually a good DSL could look kinda like this:
作为旁注,实际上一个好的DSL看起来有点像这样:
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.
回答你的问题:对于简单的例子,你提供了一个简单的绑定工作正常。