刚刚写好了boost::bind到boost::function的自动推导工作,很是兴奋。下面就是怎么用的问题了。
首先看它究竟方便了什么。
设想你有一组界面,实现一个retry的功能。包括:验证某个函数是否执行成功,执行成功出线成功的提示;执行失败出现失败的提示,并同时提示重试。
如果这么写
begin:
if(do_something()) show_success_widgets();else if(show_failure_widgets()==retry) goto begin:;
这么写,很难将这样一组模块作为一个整体重复利用,每次要写类似的逻辑。
如果我们把do_something作为一个命令丢给相应的模块,就很容易解决这样的问题。
class reuse_retry_ui
{
.......success_widget,failure_widget,other widets....
public:
try_command(function<bool()> cmd) {m_tryCmd = cmd; try command and retry.}
private:
function<bool()> m_tryCmd;
}
这样我们在需要重试函数的时候就可以简单的调用这个widget的集合,而不用自己去组织widget的出现顺序。
reuse_retry_ui_obj.try_command(bind(&test,this));
这样看起来一切都完美了。
事情总是变化的,忽然有一天,一个新需求来了,这个command需要一个参数,是一个文件名。别的都一样,就需要加一个输入框就好了。
那修改我们的reuse_retry_ui,加一个成员函数和一个成员变量m_fileTryCmd;
try_command(function<bool(string)> cmd) {m_fileTryCmd = cmd; str = getfilename(); try_command(apply(m_fileTryCmd,str));}
实现很简单,可是很遗憾,编译不过。
因为对于重载的try_command, bind出来的对象和哪个都可能match,解决的方法有两种,一种就是别用try_command这个名字了,换个try_command_1,调用者调用try_command_1。这种方法不错,但是随着日子的增多,我们也许会有try_command_2, try_command_3........。我们使用这种模式接口简单的优点就慢慢消失了。
还有一种办法就是让用户指定bind之后的function对象类型。
就需要用户调用的时候这样指定: try_command(function<void(string)>(bind....)),问题解决了,但是不是特别爽,而且如果function类型指定的和bind的不match, 又是一堆编译错误。
如果我们有了B2F, 事情就简单了。
template<class T>
try_command(T cmd) {try_command(B2F(cmd);}
template<> try_command(function<void()> cmd) {...} //same as try_command_0
template<> try_command(function<void(string)> cmd) {...} //same as try_command_1
..... any other extensions.
这样,用户所有的调用方式都是:
try_command(bind.....);
简单,就是我们想要的。