如何用C++函数实现类似三目运算符的功能
来源:互联网 发布:软件测试答辩ppt 编辑:程序博客网 时间:2024/04/29 01:21
问题引出
今天aikilis问了我二个问题:
1 下面这段代码合法吗?
( i > 0 ? i : j ) = 1;
2 如何用一个原型为quest(bool,type,type)的函数实现三目符的功能?
经试验,第一个问题的答案是肯定的,虽然原来从没这么用过。
第二个问题确实费了很多脑筋。
三目符的性质
void test0() { int i = 0, j = 0, k; ( i > 0 ? i : j ) = 3; // ok ( i > 0 ? i : 2 ) = 3; // error ( i > 0 ? 1 : j ) = 3; // error ( i > 0 ? 1 : 2 ) = 3; // error k = ( j > 0 ? i : j ); // ok k = ( j > 0 ? i : 2 ); // ok k = ( i > 0 ? 1 : j ); // ok k = ( i > 0 ? 1 : 2 ); // ok}
即在赋值右侧的时候,三目符返回左值右值都可以。
但是放在赋值左侧的时候,三目符返回值必须是左值。
所以我们的目标是实现如下代码:
void test1() { int i = 0, j = 0, k; quest( i > 0, i, j ) = 3; // ok quest( i > 0, i, 2 ) = 3; // error quest( i > 0, 1, j ) = 3; // error quest( i > 0, 1, 2 ) = 3; // error k = quest( j > 0, i, j ); // ok k = quest( j > 0, i, 2 ); // ok k = quest( i > 0, 1, j ); // ok k = quest( i > 0, 1, 2 ); // ok}
失败的尝试
1 最开始的想法,通过函数重载,输入是左值就返回左值引用,输入是右值就返回右值。
// 为左值准备的template< typename T >T& quest( bool cond, T& true_val, T& false_val ) { if( cond ) return true_val; return false_val;}// 为右值准备的template< typename T >T quest( bool cond, const T true_val, const T false_val ) { if( cond ) return true_val; return false_val;}
然而这是不行的。编译结果:
void test1() { int i = 0, j = 0, k; quest( i > 0, i, j ) = 3; // ambiguous,因为左值也可以当右值用 quest( i > 0, i, 2 ) = 3; // error quest( i > 0, 1, j ) = 3; // error quest( i > 0, 1, 2 ) = 3; // error k = quest( j > 0, i, j ); // ambiguous,因为左值也可以当右值用 k = quest( j > 0, i, 2 ); // ok k = quest( i > 0, 1, j ); // ok k = quest( i > 0, 1, 2 ); // ok}
可以看出和标准答案有两个不相符,就是当true_val和false_val都是左值时,编译器无法区分调用哪个版本。
2 然后我想到了右值引用,一查,右值引用还真有几个比较有趣的特性:
a> 右值引用作为函数参数,只能传递右值或临时变量,不能传递左值或左值引用
b> 如果在模板或者typedef中可以使用引用折叠,折叠规则如下:
- 右值引用的右值引用折叠为右值引用(T&& &&认为是T&&)
- 其它情况都认为是左值引用(T& &&认为是T&)
c> 如果传递的是左值,这时推断T是原型的时候,会组成T&&右值引用,导致绑定错误,这时编译器会聪明的推断输入是T&,从而触发引用折叠,推断出参数最终类型是T&
根据上述特性,我写出了第二个版本:
// 参数使用了右值引用,返回值使用了左值引用template < typename T >T& quest( bool cond, T&& true_val, T&& false_val ) { if( cond ) return true_val; return false_val;}
编译结果:
void test1() { int i = 0, j = 0, k; quest( i > 0, i, j ) = 3; // ok quest( i > 0, i, 2 ) = 3; // error quest( i > 0, 1, j ) = 3; // error quest( i > 0, 1, 2 ) = 3; // ok k = quest( j > 0, i, j ); // ok k = quest( j > 0, i, 2 ); // error k = quest( i > 0, 1, j ); // error k = quest( i > 0, 1, 2 ); // ok}
当传入的参数是一左值一个右值时出错倒知道怎么回事,但是第4个竟然通过了,也就是因为返回的是左值引用,所以即使我传进去两个右值,传出来的居然是一个临时变量的左值引用。
3 然后想到了上面所说c的特点,所以我将返回值写成了T,因为传入的是左值的时候,编译器会为我将T推倒为引用类型。
template < typename T >T quest( bool cond, T&& true_val, T&& false_val ) { if( cond ) return true_val; return false_val;}
可以说,这已经解决了问题的90%了。最后剩下的问题就是当传入的是一个左值一个右值怎么办,我的解决办法是增加两个函数。
最终结果
template < typename T >T quest( bool cond, T&& true_val, T&& false_val ) { if( cond ) return true_val; return false_val;}template < typename T >T quest( bool cond, T& true_val, T&& false_val ) { if( cond ) return true_val; return false_val;}template < typename T >T quest( bool cond, T&& true_val, T& false_val ) { if( cond ) return true_val; return false_val;}
参考
[1] http://en.cppreference.com/w/cpp/language/reference
[2] http://www.th7.cn/Program/cp/201403/183896.shtml
[3] http://www.2cto.com/kf/201311/260709.html
- 如何用C++函数实现类似三目运算符的功能
- 如何用android实现类似windows的画板功能
- 如何用Java实现类似c/c++指针效果
- 如何用C语言实现类似C++中的多态
- 如何用栈实现队列的功能
- 如何用DataGrid实现类似DataList多列的效果
- 如何用php实现类似博客的二级域名
- 如何用VC60实现类似windows搜索文件的功能,针对文件夹中包含的文件名进行模糊查
- 如何用c实现可执行文件的复制
- 如何用C实现C++的特性
- 如何用c语言实现CString的构造函数、析构函数和赋值函数?
- sql server中如何用sql实现类似于mysql的CONCAT()函数的功能?
- 如何用C的CGI实现网页的分页显示功能?
- 如何用C语言编写幂运算的代码?救急!!!
- 如何用Java实现两个文件的异或运算
- 如何用算法实现多国语言的自动识别功能?
- 如何用delphi语言实现结束指定进程的功能
- c++中如何用string实现CString格式化的功能
- 15_09_18 Android 程序结构图
- Echarts Force力导向图实现节点可折叠
- Processing 练习(10) - 条形码
- Android JSON(Fastjson,Gson)
- Android Service——活动和服务进行通信
- 如何用C++函数实现类似三目运算符的功能
- C# 窗口连接数据库 显示数据
- java 版 jquery jcrop截图并上传
- 封装详解
- 队列
- unity之XML
- 0124 WEB安全实战(三)XSS 攻击的防御【基础】
- 数据结构之 栈
- [BZOJ1623][Usaco2008 Open]Cow Cars 奶牛飞车