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