(转)条件运算符

一,缘起
平常都是把条件运算符当作简化if/else代码行数的另一种形式,今天偶然写下了下面这砣代码,就是让第二个和第三个表达式的具有不同类型,看看sizeof的结果:

#include 
int main()
{
int n = sizeof(( true ? 3 : 3.14);    // 不同的类型
    printf(“Type size: %d\n”, n);
return 0;
}

结果是:  Type size: 8


二,细节
一个条件操作符是下面这样的形式:
exp1 ? exp2 : exp3
表达式exp1总是会被求值。exp2和exp3是否被执行依赖于exp1的值,如果exp1为真则exp2会被求值,否则exp3被求值。
Side Effect:
在执行exp2或者exp3之前,exp1的所有side effect必须全部求值或者更新完成,因为条件操作符的第一个操作数求值之后就是一个sequence point。如果exp2和exp3都有side effect,那么只有一个会被求值。
返回类型:
条件操作符的返回类型取决于exp2和exp3类型,编译器会检查exp2(可能是一个class type)能否转换为exp3或者exp3能否转换为exp2,如果两个都不满足,编译器就会抛出一个错误。


三,实践
只要exp2或expr3能转换为对方的类型,那么条件操作符就可以通过编译器,如果它们之间没有能够转换的规则,自然过不了编译器这一关,如下面这行代码:

sizeof(true ? “text” : 3.14);    // error 
sizeof(true ? “text” : 0);    // OK, bug or feature?

为了利用C++给我们提供的强类型支持,我们应该在实践中让exp2和exp3的类型保持一致。
另外,BOOST_FOREACH里面用到了条件操作符的这个技巧来萃取容器表达式类型,同时避免对表达式求值,以此达到对rvalue的完美支持,其中的代码如下:

 

// 类型包装器
template< class T > struct type2type {};
// 转换T到type2type
template< class T >
type2type< T > encode_type( T const & t )
{
return type2type< T >();
}
// 定义了到any2type的转换
struct any_type
{
    template< class T >
operator type2type< T > () const
    {
return type2type< T >();
    }
};
// 将表达式的类型转换为type2type< expression>,并避免对 expression求值
#define ENCODED_TYPEOF( expression )         ( true ? any_type() : encode_type( expression ) )

 

ENCODED_TYPEOF(expression)会被展开为 (true ? any_type() : encode_type(expression)),exp2的类型为any_type,exp3的类型为type2type<expression>,两个表达式的类型要一致,type2type<expression>又不能转换为any_type,所以只有给any_type定义一个转换操作符,让any_type能够转换为type2type<expression>。
最后我们得到ENCODE_TYPEOF(expression)的类型为type2type< expression>,并且没有对 expression求值。
参考:
http://drdobbs.com/cpp/184401310
http://geeksforgeeks.org/?p=9205
http://www.artima.com/cppsource/foreach2.html

posted @ 2012-04-27 15:24  ForFreeDom  阅读(337)  评论(0编辑  收藏  举报