拯救你的字符串 : 完美救赎之终极奥义

来源:互联网 发布:c语言中的指针 编辑:程序博客网 时间:2024/04/29 23:38

引言:我希望看我的文章的朋友都能够去把我的代码编译一次,这样会发现理解我的文章很轻松。我给的代码都是直接无需修改就可编译并运行的。

 

前一篇文章http://blog.csdn.net/zy498420/archive/2010/11/10/6000129.aspx说到的种子皮在vc6的不完美适用问题,被彻底的解决了。剃了个头恰好就有思路了。

 

解决的方法很简单,让前一篇文章所说的bug在且仅在vc6中出现,完美。以毒攻毒,以bug1解决bug2!!

 

原理:vc6重载决议能力有限,但是却允许右值(临时值)传递给非const引用参数。当然同等条件它的重载决议优先选择带const引用参数(这个规则按标准原本只能用在左值上)的函数。

 

template <typename D, typename L, typename R, typename C>

inline const _et_private::binary_tree_ref<D, _et_private::binary_tree_ref<D, L, R>, C >

    operator + (const _et_private::binary_tree_ref<D, L, R>& lhs, const C& rhs){

    return _et_private::binary_tree_ref<D, _et_private::binary_tree_ref<D, L, R>, C > (lhs, rhs);

}

 

template <typename D, typename L, typename R, typename C>

inline const _et_private::binary_tree_ref<D, C, _et_private::binary_tree_ref<D, L, R> >

    operator + (const C& lhs, const _et_private::binary_tree_ref<D, L, R>& rhs){

    return _et_private::binary_tree_ref<D, C, _et_private::binary_tree_ref<D, L, R> > (lhs, rhs);

}

 

瞧,如果C类型也是binary_tree_ref时,编译器就不知道如何2选1了。符合标准的编译器支持对这种情况进行特化来帮助选择,然而vc6对于特化后的函数并没有提升它的重载优先级,而是像二师兄那样傻乎乎的问:又来了一个,3选1,选哪个呢?如果我是观音,我也想踢他了。

 

 

解决:把第2个函数的第2个参数去掉const 修饰

 

template <typename D, typename L, typename R, typename C>

inline const _et_private::binary_tree_ref<D, C, _et_private::binary_tree_ref<D, L, R> >

    operator + (const C& lhs,  _et_private::binary_tree_ref<D, L, R>& rhs){

    return _et_private::binary_tree_ref<D, C, _et_private::binary_tree_ref<D, L, R> > (lhs, rhs);

}

 

此时C若不是binary_tree_ref,就选择这个新函数(根据标准,把右值(临时值)传递给非const引用参数,编译器会抱错gcc。icc居然只给出警告,不完全算错的原因在于这个可能非法的引用我们永远不去解引用!!所以持有一个可能非法的引用并不会影响程序的运行,这也是这里vc6的“违法”行为居然没有任何坏效果的原因。不过icc是真聪明(真正的分析了inline函数内部的情况发现这个错误不会被触发),gcc是死守规矩的良民,而vc6是纯粹的瞎猫遇到了死老鼠。)。

如果C是binary_tree_ref,根据const永远优先的重载决议原则,vc6自动去选择第一个。

 

其实选择哪一个函数都是一样的,我们这里需要做的就是帮编译器做出选择。向左转还是向右转,这不是一个问题,只要你勇敢的迈出你的脚步。

 

好了,上完整代码。种皮和播种2个方法一起贴了上来,供大家参考,种皮和播种2个方法经过了非常多的测试,2者之间效率几乎没有任何区别。没有任何一个编译器能够对其中一种方法能多做一些优化。播种这一招的保留我始终觉得是有意义的。另外我对播种干脆做一个限制:必须放在最左端,不再允许放在第1和第2之间。有些接口,简单些更好用,太通用反而让人郁闷,守规矩总是一件好事。现在胡乱播种有可能编译器会报错!

 

 

 

原创粉丝点击