C++ 是一个强类型语言。不过,在实践中,我们总是可以写出这样的代码:“ 1 + 5.0f; ”,其中“ 1 ” 是整数类型,而“ 5.0f ”是一个浮点类型。我们甚至可以写出更惊人的代码,像这样:“ a + b; ”,假定“ a ”及“ b ”都是某个类的实例。这是因为编译器将为我们产生执行必要、合适转换的代码。在这一节中,我们将看到编译器在背后使用的转换,及由语言标准所制定的转换规则。
我们首先从函数 can_convert_arg 开始,该函数用于测试两个指定的类型是否匹配。
5996 bool
5997 can_convert_arg (tree to, tree from, tree arg) in call.c
5998 {
5999 tree t = implicit_conversion (to, from, arg, LOOKUP_NORMAL);
6000 return (t && ! ICS_BAD_FLAG (t));
6001 }
由其名字所显示,由下面函数执行的转换,是编译器可以自由使用的,只要它觉得合适。 它是 C++ 语言一个有趣及强大的特性;而且经常给程序员,甚至老鸟带来困惑。【 3 】,章节 13.3.3 .1 “隐含转换序列”详细解释了什么是隐式转换:
1. 一个隐式转换序列是,把一个函数调用中的一个实参转换到对应形参的类型的,转换序列。如条文 4 所定义,这个转换序列是一个隐式转换,这意味着它遵守对象初始化,及单个表达式引用( reference by a single expression )的规则( 8.5 , 8.5.3 )。 2. 隐式转换序列只关心实参的类型, cv- 限定( cv-qualification ),及左值性( lvalueness );以及如何转换这些来匹配形参的对应属性。其他属性,例如实参的生命周期,存储类别,对齐,或访问性,及实参是否是一个位域( bit-field ),都被忽略。因而,虽然对于一个指定的形参 - 实参对可以定义出一个隐式转换序列,在最后的分析中,该从实参到形参的转换仍可能被发现是错误的。 3. 一个良好的隐式转换序列是以下形式之一: — 一个标准转换序列( 13.3.3 .1.1 ), — 一个用户定义转换序列( 13.3.3 .1.2 ),或者 — 一个省略( ellipsis )转换序列( 13.3.3 .1.3 )。 4. 不过,当考虑由 13.3.1 .3 选定的用于一个类拷贝初始化第二步中临时对象拷贝,或由 13.3.1.4 , 13.3.1.5 ,或 13.3.1.6 中所有情况下选定的,一个用户定义转换函数的实参时,只允许标准转换序列及省略转换序列。 5. 在形参类型是一个引用的情况下,参见 13.3.3 .1.4. (引用绑定 reference binding ) 6. 当形参类型不是一个引用时,隐式转换序列从实参表达式塑造出形参的一个拷贝初始化。该隐式转换序列被要求把实参表达式转换到形参类型的一个右值。 [ 注意:当该形参是一个类类型,这是一个以条文 13 为目的的概念上的转换( this is a conceptual conversion defined for the purposes of clause 13 );事实上的初始化依据构造函数来定义,而不是一个转换 ] 。任何最上层的 cv- 限定上的差异,被初始化本身所包括,不会构成一个转换。 [ 例如:一个具有类型 A 的形参可以被一个具有类型 const A 的实参初始化。这个情形下的隐式转换序列是恒等序列( the identity sequence );从 const A 到 A ,不包含“转换” ] 。当形参具有一个类类型,并且实参表达式具有相同的类型,该隐式转换序列是一个恒等转换( identity conversion )。当形参具有一个类类型,而实参表达式具有一个派生类类型,隐式转换序列是一个派生类到基类的 derived-to-base 转换。 [ 注意:没有这样的标准转换;这个 derived-to-base 转换仅存在于隐式转换序列的描述中 ] 。一个 derived-to-base 转换具有转换等级( Conversion rank )( 13.3.3 .1.1 )。 7. 在所有的上下文中,当转换到隐含对象形参,或转换到一个赋值操作的左侧操作数时, 仅允许不构建用于结果的临时对象的标准转换序列。 8. 如果匹配一个实参到一个形参类型不要求转换,这个隐式转换序列是包含恒等转换的标准转换序列( 13.3.3 .1.1 )。 9. 如果不能找到一个转换序列来转换一个实参到形参的类型,或者该转换是错误的,则不能形成隐式转换序列。 10. 如果存在多个不同的转换序列把实参转换到形参的类型,与该形参关联的隐式转换序列被定义为显示出二义性转换序列的唯一的转换序列( the unique conversion sequence designated the ambiguous conversion sequence )。出于以 13.3.3 .2 中所描述的隐式转换排名的目的,二义性转换序列被作为用户定义序列来处理,即与其他用户定义转换序列无法区分(二义性转换序列被安排做与用户定义转换序列等级相同,是因为对于一个实参,仅当涉及不同的用户定义转换时,才可能存在多个转换序列。二义性转换序列与其他用户转换序列不可区分,在于它至少代表了 2 个用户定义转换序列,每个具有不同的用户定义转换,而其他用户定义转换序列必然与其中至少一个不能区分。 这个规则防止一个函数因为其某个形参的二义性转换序列,而成为不可行。考虑这个例子, class B; class A { A (B&); }; class B { operator A (); }; class C { C (B&); }; void f(A) { } void f(C) { } B b; f(b); // 二义性的,因为 b -> C 通过构造函数,而 // b -> A 通过构造函数或转换函数 如果没有这个规则,对于调用 f(b) , f(A) 将被取消作为可行函数,从而导致重载解析选择 f(C) 作为实际的调用,尽管显然地,它不是最佳选择。另一方面,如果声明了一个 f(B) ,那么 f(b) 将被解析为 f(B) ,因为与 f(B) 的完全匹配优于匹配 f(A) 所要求的序列。 如果一个使用二义性转换序列的函数被选择为最佳可行函数,该调用将是错误的,因为该调用中某个实参的转换是有二义性的。 11. 上面提及的隐式转换序列的 3 种形式定义在以下子条文中。 |
在深入代码之前,我们首先要阐明左值( lvalue )及右值( rvalue )的概念。一个左值是指一个对象或函数。它必须是一个可取值的实体。即如果它是指对象的话,该对象应该能够被放在一个赋值操作的左手侧(这也是为什么它被称为左值)。而非左值的就被称为右值(它们不能用在赋值操作的左手侧)。
1097 static tree
1098 implicit_conversion (tree to, tree from, tree expr, int flags) in call.c
1099 {
1100 tree conv;
1101
1102 if (from == error_mark_node || to == error_mark_node
1103 || expr == error_mark_node)
1104 return NULL_TREE;
1105
1106 if (TREE_CODE (to) == REFERENCE_TYPE)
1107 conv = reference_binding (to, from, expr, flags);
1108 else
1109 conv = standard_conversion (to, from, expr, flags);
1110
1111 if (conv)
1112 return conv;
1113
1114 if (expr != NULL_TREE
1115 && (IS_AGGR_TYPE (from)
1116 || IS_AGGR_TYPE (to))
1117 && (flags & LOOKUP_NO_CONVERSION) == 0)
1118 {
1119 struct z_candidate *cand;
1120
1121 cand = build_user_type_conversion_1
1122 (to, expr, LOOKUP_ONLYCONVERTING);
1123 if (cand)
1124 conv = cand->second_conv;
1125
1126 /* We used to try to bind a reference to a temporary here, but that
1127 now handled by the recursive call to this function at the end
1128 of reference_binding. */
1129 return conv;
1130 }
1131
1132 return NULL_TREE;
1133 }
看到转换处理函数可能会相互递归,在这里,为了处理引用类型,该函数再一次调用了 reference_binding 。不过,因为我们正在表达式的树中前进,只要没有回环的依赖,就不会有无限递归。因为 C++ 是要求使用前必须声明的语言,相互依赖是非法的;解析器应该能够找出这个非法的形式。
【 3 】章节 13.3.3 .1.1 “标准转换序列”给出关于序列的细节。
1. 表 9 总结了在条文 4 中定义的转换( “标准转换”,【 3 】的章节 4 )并划分为 4 个不相交的类别:左值转型( Lvalue Transformation ),限定调整( Qualification Adjustment ),提升( Promotion ),以及转换( Conversion )。 [ 注意:这些分类就左值性, cv- 限定性,及数据表达方面而言,是正交的:左值转型不会改变类型的 cv- 限定性及数据表达;限定调整不会改变类型的左值性及数据表达;而提升及转换不会改变类型的左值性及 cv- 限定性。 ] 2. [ 注意: 如条文 4 所描述,应该标准转换序列要么本身是恒等转换(即,没有转换),要么包含其他属于这 4 个类别的 1 到 3 个转换( consists of one to three conversions from the other four categories )。在单个标准转换序列中,每个类别最多允许一个转换。如果在该序列中有 2 个或以上的转换,这些转换以规范的次序应用:左值转型 ,提升 或转换 ,限定调整 。 —end note ] 3. 在表 9 中的每个转换都具有关联的等级(精确匹配,提升,或转换)。这些都用于评价标准转换序列( 13.3.3 .2 )。一个转换序列的等级通过考察序列中的每个转换的等级,及任意引用绑定的等级( rank of any reference binding )( 13.3.3.1.4 )来决定。如果任意一个具有转换等级,该序列就是转换等级;否则,如果任意一个具有提升等级,该序列就是提升等级;否则,该序列就是精确匹配等级。 表 9 : - 转换
|
下面我们跳过 472~479 行对重载的解析(在后面有关引用绑定的章节再来看它,记得 type_unknown_p 返回 true ,如果 expr 是一个重载)。还要记住下面的 standard_conversion 处理隐式转换,它只考虑上面提到的转换;千万不要把它与强制转换混淆。
456 static tree
457 standard_conversion (tree to, tree from, tree expr, int flags) in call.c
458 {
459 enum tree_code fcode, tcode;
460 tree conv;
461 bool fromref = false;
462
463 to = v (to);
464 if (TREE_CODE (from) == REFERENCE_TYPE)
465 {
466 fromref = true;
467 from = TREE_TYPE (from);
468 }
469 to = strip_top_quals (to);
470 from = strip_top_quals (from);
471
472 if ((TYPE_PTRFN_P (to) || TYPE_PTRMEMFUNC_P (to))
473 && expr && type_unknown_p (expr))
474 {
475 expr = instantiate_type (to, expr, tf_conv);
476 if (expr == error_mark_node)
477 return NULL_TREE;
478 from = TREE_TYPE (expr);
479 }
480
481 fcode = TREE_CODE (from);
482 tcode = TREE_CODE (to);
483
484 conv = build1 (IDENTITY_CONV, from, expr);
485
486 if (fcode == FUNCTION_TYPE)
487 {
488 from = build_pointer_type (from);
489 fcode = TREE_CODE (from);
490 conv = build_conv (LVALUE_CONV, from, conv);
491 }
492 else if (fcode == ARRAY_TYPE)
493 {
494 from = build_pointer_type (TREE_TYPE (from));
495 fcode = TREE_CODE (from);
496 conv = build_conv (LVALUE_CONV, from, conv);
497 }
498 else if (fromref || (expr && lvalue_p (expr)))
499 conv = build_conv (RVALUE_CONV, from, conv);
500
501 /* Allow conversion between `__complex__' data types. */
502 if (tcode == COMPLEX_TYPE && fcode == COMPLEX_TYPE)
503 {
504 /* The standard conversion sequence to convert FROM to TO is
505 the standard conversion sequence to perform componentwise
506 conversion. */
507 tree part_conv = standard_conversion
508 (TREE_TYPE (to), TREE_TYPE (from), NULL_TREE, flags);
509
510 if (part_conv)
511 {
512 conv = build_conv (TREE_CODE (part_conv), to, conv);
513 ICS_STD_RANK (conv) = ICS_STD_RANK (part_conv);
514 }
515 else
516 conv = NULL_TREE;
517
518 return conv;
519 }
520
521 if (same_type_p (from, to))
522 return conv;
484 行为恒等转换构建了 IDENTITY_COV 。 *_CONV 节点的 type 表示转换的源类型,而它的第一个操作数是需要转换的表达式。因此转换序列将是一个大的嵌套的 *_CONV 节点,最上层的 *_CONV 是最后执行的,而最里层的是首先执行且永远是 IDENTITY_CONV 。
在前端的内部为转换定义了如下的等级,而不是如上面表 9 所定义的那些。注意到值越小表示等级越优先。
343 #define IDENTITY_RANK 0 in call.c
344 #define EXACT_RANK 1
345 #define PROMO_RANK 2
346 #define STD_RANK 3
347 #define PBOOL_RANK 4
348 #define USER_RANK 5
349 #define ELLIPSIS_RANK 6
350 #define BAD_RANK 7
在内部可以产生的转换有: IDENTITY_CONV , LVALUE_CONV , QUAL_CONV , STD_CONV , PTR_CONV , PMEM_CONV , BASE_CONV , REF_BIND , USER_CONV , AMBIG_CONV ,及 RVALUE_CONV 。
408 static tree
409 build_conv (enum tree_code code, tree type, tree from) in call.c
410 {
411 tree t;
412 int rank = ICS_STD_RANK (from);
413
414 /* We can't use buildl1 here because CODE could be USER_CONV, which
415 takes two arguments. In that case, the caller is responsible for
416 filling in the second argument. */
417 t = make_node (code);
418 TREE_TYPE (t) = type;
419 TREE_OPERAND (t, 0) = from;
420
421 switch (code)
422 {
423 case PTR_CONV:
424 case PMEM_CONV:
425 case BASE_CONV:
426 case STD_CONV:
427 if (rank < STD_RANK)
428 rank = STD_RANK;
429 break ;
430
431 case QUAL_CONV:
432 if (rank < EXACT_RANK)
433 rank = EXACT_RANK;
434
435 default :
436 break ;
437 }
438 ICS_STD_RANK (t) = rank;
439 ICS_USER_FLAG (t) = (code == USER_CONV || ICS_USER_FLAG (from));
440 ICS_BAD_FLAG (t) = ICS_BAD_FLAG (from);
441 return t;
442 }
在上面的函数里, ICS_STD_RANK 将保存所见到的最大的等级值,在后面的章节我们将看到它的使用。
而在上面 standard_conversion 的 486 及 492 行处理函数到指针与数组到指针的转换,它们在【 3 】条文 4.2 “数组到指针转换”及条文 4.3 “函数到指针转换”中描述如下:
1. 具有类型“ array ofN T ”或“ array of unknown bound of T ”的一个左值或右值可以被转换到一个类型为“ pointer to T ”的右值。其结果是指向数组第一个元素的指针。 2. 一个非宽字符的字符串( 2.13.4 )可以被转换到一个类型为“ pointer to char ”的右值;一个宽字符的字符串可以被转换到一个类型为“ pointer to wchar_t ”的右值。在这两种情况中,其结果是指向数组第一个元素的指针。仅当目标类型是一个明确恰当的指针时,才考虑该转换;而当仅是一般的从左值到右值的转换时,不考虑该转换。 [ 注意:不推荐使用这个转换。参见附录 D 。 ] 出于在重载解析( 13.3.3.1.1 )中评估的目的,这个转换被视为一个跟有一个限定转换( 4.4 )的数组到指针的转换。 [ 例如:作为一个数组到指针转换, "abc" 被转换到“ pointer to const char ”;然后作为一个限定转换,转换到“ pointer to char ”。 ] |
1. 函数类型 T 的一个左值可以被转换到类型“ pointer to T ”的一个右值。其结果是指向该函数的指针。(这个转换不能应用于非静态成员函数,因为一个非静态成员函数的左值是无法得到的。) 2. [ 注意:参见 13.4 ,用于重载函数的补充规则。 ] |
注意两个条文的条款 1 ,类型“ pointer to T ”的右值表示该指针本身是不能修改的,但其内容可以改变。例如:
char a[10];
char *p = …;
a = p; // a is converted to rvalue of char*, assignment not allowed
*(a+1) = *p; // object pointed by a+1 is lvalue, it is OK
与下面的条文相比,这 2 个条文包含了指针类型的构建,前端必须能从其他左值转型中区分出这两种情况。因此前端为它们使用了 LVALUE_CONV 。
然后在 standard_conversion 中,如果满足在 498 行条件,需要实现【 3 】条文 4.1 “左值到右值转换”的条款 1 。这一次前端使用 RVALUE_CONV 。 LVALUE_CONV 与 RVALUE_CONV 的一个区别在于当构建 LVALUE_CONV 时,我们已经知道这个右值了(在 488 及 494 行构建的指针类型),而对于 RVALUE_CONV ,在这一点上,这个右值是未知的,在后面前端需要调用 decay_conversion 来执行真正的转换。
1. 一个非函数,非数组类型的左值( 3.10 )可以被转换到一个右值。如果 T 是一个未完成的类型,必须这个转换的程序就是错误的。如果该左值引用的对象不是一个类型 T 或从 T 派生类型的对象,或者该对象未初始化,必须这个转换的程序具有不确定的行为。如果 T 是非类类型,该右值的类型是 T 的非 cv 限定的版本。否则,该右值的类型是 T 。 [ 在 C++ 类中,右值可以具有 cv- 限定的类型(因为它们都是对象)。这不同于 ISO C ,在 ISO C 里,非左值不能是 cv- 限定的类型。 ] 2. 由左值表示的对象的值是右值的结果( The value contained in the object indicated by the lvalue is the rvalue result )。当在 sizeof ( 5.3.3 )的操作数中发生一个左值到右值的转换,包含在被引用对象中的值是不可访问的,因为这个操作符不会对其操作数求值。 |
下面的函数,给定表达式 ref ,它可以判断这个表达式是否为左值。看到上面为指针类型构建的 LVALUE_CONV ,该函数判定为右值。这个函数应该被仔细研究。
211 int
212 lvalue_p (tree ref) in tree.c
213 {
214 return
215 (lvalue_p_1 (ref, /*class rvalue ok*/ 1) != clk_none);
216 }
而我们要区分的左值的类型如下。
2964 typedef enum cp_lvalue_kind { in cp-tree.h
2965 clk_none = 0, /* Things that are not an lvalue. */
2966 clk_ordinary = 1, /* An ordinary lvalue. */
2967 clk_class = 2, /* An rvalue of class-type. */
2968 clk_bitfield = 4, /* An lvalue for a bit-field. */
2969 clk_packed = 8 /* An lvalue for a packed field. */
2970 } cp_lvalue_kind ;
在【 3 】,条文 3.10 (左值及右值)给出如下解释。
1. 任一表达式要么是左值,要么是右值。 2. 左值指一个对象或函数。一些右值表达式——它们具有类或 cv- 限定的类类型——也指向对象(调用构造函数或返回一个引用对象的类类型的函数的表达式,而且在这样的对象上可以调用成员函数,但这些表达式不是左值)。 3. [ 注意:某些内建操作符及函数调用会产生左值。 [ 例如:如果 E 是一个指针类型的表达式,那么 *E 是一个左值的表达式,引用 E 所指向的对象或函数。另一个例子,函数 int& f(); 产生一个左值,因此调用 f() 是一个左值表达式。 ]] 4. [ 注意:某些内建操作符期望左值的操作数。 [ 例如:内建的赋值操作符都期望其左侧操作数是左值 ] 。其他内建操作符产生右值,而一些则期望右值。 [ 例如:一元及二元操作符 + 期望右值的参数,并产生右值的结果 ] 。在条文 5 对每个内建操作符的讨论说明了它是否期望左值操作数,及它是否产生左值结果 ] 。 5. 调用一个不返回引用的函数的结果是一个右值。用户定义操作符是函数,这些操作符是否期望或产生左值,由其参数及返回类型决定。 6. 保存一个由到非引用类型的转换( cast )引致的临时对象的表达式是一个右值(这包括使用函数记号(即,显式类型转换, 5.2.3 )所显式创建的对象。 7. 在任何时候,一个左值出现在一个期望右值的上下文中,该左值被转换为一个右值;参见 4.1 , 4.2 ,及 4.3 。 8. 在 8.5.3 对引用初始化,及在 12.2 对临时对象的讨论,显示了在其他重要的上下文中左值及右值的行为。 9. 类右值可以有 cv- 限定的类型;非类右值总是非 cv- 限定的类型。右值应该总是具有完成的类型或 void 类型;除了这些类型。左值还可以具有未完成的类型。 10. 为了修改一个对象,该对象的一个左值是必要的;除了类类型的右值,在特定的环境下,可以用于修改其所指对象。 [ 例如:对一个对象调用成员函数( 9.3 )可以修改这个对象。 ] 11. 函数不可修改,但函数的指针是可修改的。 12. 一个未完成类型的指针是可修改的。在程序中的某一点,当所指向的类型完成,该指针所指向的对象亦可修改。 13. 一个 const- 限定的表达式的指称对象不应该被修改(通过这个表达式),除非它具有类类型,并且有一个可变( mutable )成分,该成分可以被修改( 7.1.5.1 )。 14. 如果一个表达式可以被用于修改它所引用的对象,该表达式被称为可修改。一个尝试通过一个不可修改的左值或右值表达式来修改对象的程序是不合法的。 15. 如果一个程序尝试,通过以下类型以外的一个左值,来访问一个对象的存储值,其行为是未不可预测的(这个列表的意图是指出那些一个对象可能或不可能被别名( alias )的环境: — 该对象的动态类型( dynamic type ), — 该对象的动态类型的一个 cv- 限定的版本, — 该对象的动态类型所对应的有符号或无符号类型, — 该对象的动态类型的一个 cv- 限定版本所对应的有符号或无符号类型, — 一个聚合或 union 类型,在其成员中包含上述类型之一(包括,递归地,一个子聚合或被包含的( contained ) union 的一个成员), — 该对象的动态类型的基类类型(可能有 cv- 限定), — 字符或无符号字符类型。 |
考虑下面对非静态方法的处理,因为非静态方法必须这样调用:“ a.fa(); ”,其中给定的对象可能是不可取址的(例如,在语句“ A().fa(); ”中,“ A() ”返回了一个右值),非静态方法被认为是右值。另外,表达式“ A().fa(); ”可以修改这个对象,因此如果不要求严格的左值(参数 treat_class_rvalues_as_lvalues 为 1 ),“ A() ”可被视为左值。注意 156 行的 TARGET_EXPR ,它将封装刚才提及的“ A() ”返回的临时对象(注意 161 行的注释)。
62 static cp_lvalue_kind
63 lvalue_p_1 (tree ref, in tree.c
64 int treat_class_rvalues_as_lvalues)
65 {
66 cp_lvalue_kind op1_lvalue_kind = clk_none;
67 cp_lvalue_kind op2_lvalue_kind = clk_none;
68
69 if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
70 return clk_ordinary;
71
72 if (ref == current_class_ptr )
73 return clk_none;
74
75 switch (TREE_CODE (ref))
76 {
77 /* preincrements and predecrements are valid lvals, provided
78 what they refer to are valid lvals. */
79 case PREINCREMENT_EXPR:
80 case PREDECREMENT_EXPR:
81 case SAVE_EXPR:
82 case UNSAVE_EXPR:
83 case TRY_CATCH_EXPR:
84 case WITH_CLEANUP_EXPR:
85 case REALPART_EXPR:
86 case IMAGPART_EXPR:
87 return lvalue_p_1 (TREE_OPERAND (ref, 0),
88 treat_class_rvalues_as_lvalues);
89
90 case COMPONENT_REF:
91 op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
92 treat_class_rvalues_as_lvalues);
93 /* In an expression of the form "X.Y", the packed-ness of the
94 expression does not depend on "X". */
95 op1_lvalue_kind &= ~clk_packed;
96 /* Look at the member designator. */
97 if (!op1_lvalue_kind
98 /* The "field" can be a FUNCTION_DECL or an OVERLOAD in some
99 situations. */
100 || TREE_CODE (TREE_OPERAND (ref, 1)) != FIELD_DECL)
101 ;
102 else if (DECL_C_BIT_FIELD (TREE_OPERAND (ref, 1)))
103 {
104 /* Clear the ordinary bit. If this object was a class
105 rvalue we want to preserve that information. */
106 op1_lvalue_kind &= ~clk_ordinary;
107 /* The lvalue is for a bitfield. */
108 op1_lvalue_kind |= clk_bitfield;
109 }
110 else if (DECL_PACKED (TREE_OPERAND (ref, 1)))
111 op1_lvalue_kind |= clk_packed;
112
113 return op1_lvalue_kind;
114
115 case STRING_CST:
116 return clk_ordinary;
117
118 case VAR_DECL:
119 if (TREE_READONLY (ref) && ! TREE_STATIC (ref)
120 && DECL_LANG_SPECIFIC (ref)
121 && DECL_IN_AGGR_P (ref))
122 return clk_none;
123 case INDIRECT_REF:
124 case ARRAY_REF:
125 case PARM_DECL:
126 case RESULT_DECL:
127 if (TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
128 return clk_ordinary;
129 break ;
130
131 /* A currently unresolved scope ref. */
132 case SCOPE_REF:
133 abort ();
134 case MAX_EXPR:
135 case MIN_EXPR:
136 op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
137 treat_class_rvalues_as_lvalues);
138 op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
139 treat_class_rvalues_as_lvalues);
140 break ;
141
142 case COND_EXPR:
143 op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),
144 treat_class_rvalues_as_lvalues);
145 op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 2),
146 treat_class_rvalues_as_lvalues);
147 break ;
148
149 case MODIFY_EXPR:
150 return clk_ordinary;
151
152 case COMPOUND_EXPR:
153 return lvalue_p_1 (TREE_OPERAND (ref, 1),
154 treat_class_rvalues_as_lvalues);
155
156 case TARGET_EXPR:
157 return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
158
159 case CALL_EXPR:
160 case VA_ARG_EXPR:
161 /* Any class-valued call would be wrapped in a TARGET_EXPR. */
162 return clk_none;
163
164 case FUNCTION_DECL:
165 /* All functions (except non-static-member functions) are
166 lvalues. */
167 return (DECL_NONSTATIC_MEMBER_FUNCTION_P (ref)
168 ? clk_none : clk_ordinary);
169
170 case NON_DEPENDENT_EXPR:
171 /* We must consider NON_DEPENDENT_EXPRs to be lvalues so that
172 things like "&E" where "E" is an expression with a
173 non-dependent type work. It is safe to be lenient because an
174 error will be issued when the template is instantiated if "E"
175 is not an lvalue. */
176 return clk_ordinary;
177
178 default :
179 break ;
180 }
181
182 /* If one operand is not an lvalue at all, then this expression is
183 not an lvalue. */
184 if (!op1_lvalue_kind || !op2_lvalue_kind)
185 return clk_none;
186
187 /* Otherwise, it's an lvalue, and it has all the odd properties
188 contributed by either operand. */
189 op1_lvalue_kind = op1_lvalue_kind | op2_lvalue_kind;
190 /* It's not an ordinary lvalue if it involves either a bit-field or
191 a class rvalue. */
192 if ((op1_lvalue_kind & ~clk_ordinary) != clk_none)
193 op1_lvalue_kind &= ~clk_ordinary;
194 return op1_lvalue_kind;
195 }
上面的 NON_DEPENDENT_EXPR 是用于非类型依赖,但出现在模板中的表达式的占位符。看到 INDIRECT_REF 是左值(不过指针本身是右值,它是上面条款 3 所描述的情况);而普通的变量也是左值( 118 行);另外如果数组被引用,其引用是左值,否则该数组将被衰退为右值的指针类型。接着注意 149 行的 MODIFY_EXPR ,它毫无疑问是左值,而随后的 COMPOUND_EXPR 依赖于其第二个操作数。而对于可能包含左值操作数的表达式, lvalue_p_1 递归入操作数。
值得注意的是,“ int& f(); ”的调用表达式“ f(); ”是一个左值,但是像“ f() = 5; ”这样的表达式是非法的;这个左值可以被直接使用的情况是把“ f() ”用作参数, 125 行的 PARM_DECL 覆盖了这个用法;因此不在 PARM_DECL 里的 CALL_EXPR 被视为右值。另外, PARM_DECL , RESULT_DECL , ARRAY_REF , INDIRECT_REF 作为左值,其类型不能是类的非静态方法。
standard_conversion (continue)
524 if ((tcode == POINTER_TYPE || TYPE_PTR_TO_MEMBER_P (to))
525 && expr && null_ptr_cst_p (expr))
526 conv = build_conv (STD_CONV, to, conv);
527 else if (tcode == POINTER_TYPE && fcode == POINTER_TYPE
528 && TREE_CODE (TREE_TYPE (to)) == VECTOR_TYPE
529 && TREE_CODE (TREE_TYPE (from)) == VECTOR_TYPE
530 && ((*targetm .vector_opaque_p) (TREE_TYPE (to))
531 || (*targetm .vector_opaque_p) (TREE_TYPE (from))))
532 conv = build_conv (STD_CONV, to, conv);
533 else if ((tcode == INTEGER_TYPE && fcode == POINTER_TYPE)
534 || (tcode == POINTER_TYPE && fcode == INTEGER_TYPE))
535 {
536 /* For backwards brain damage compatibility, allow interconversion of
537 pointers and integers with a pedwarn. */
538 conv = build_conv (STD_CONV, to, conv);
539 ICS_BAD_FLAG (conv) = 1;
540 }
541 else if (tcode == ENUMERAL_TYPE && fcode == INTEGER_TYPE)
542 {
543 /* For backwards brain damage compatibility, allow interconversion of
544 enums and integers with a pedwarn. */
545 conv = build_conv (STD_CONV, to, conv);
546 ICS_BAD_FLAG (conv) = 1;
547 }
注意上面,指针与整数及整数与枚举值之间的转换,在 C++ 的语言环境中,都是不良转换(不过在 C 下,仅会给出警告)。因此这些转换会被记录,并给予最低的等级。
standard_conversion (continue)
548 else if ((tcode == POINTER_TYPE && fcode == POINTER_TYPE)
549 || (TYPE_PTRMEM_P (to) && TYPE_PTRMEM_P (from)))
550 {
551 tree to_pointee;
552 tree from_pointee;
553
554 if (tcode == POINTER_TYPE
555 && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (from),
556 TREE_TYPE (to)))
557 ;
558 else if (VOID_TYPE_P (TREE_TYPE (to))
559 && !TYPE_PTRMEM_P (from)
560 && TREE_CODE (TREE_TYPE (from)) != FUNCTION_TYPE)
561 {
562 from = build_pointer_type
563 (cp_build_qualified_type (void_type_node,
564 cp_type_quals (TREE_TYPE (from))));
565 conv = build_conv (PTR_CONV, from, conv);
566 }
567 else if (TYPE_PTRMEM_P (from))
568 {
569 tree fbase = TYPE_PTRMEM_CLASS_TYPE (from);
570 tree tbase = TYPE_PTRMEM_CLASS_TYPE (to);
571
572 if (DERIVED_FROM_P (fbase, tbase)
573 && (same_type_ignoring_top_level_qualifiers_p
574 (TYPE_PTRMEM_POINTED_TO_TYPE (from),
575 TYPE_PTRMEM_POINTED_TO_TYPE (to))))
576 {
577 from = build_ptrmem_type (tbase,
578 TYPE_PTRMEM_POINTED_TO_TYPE (from));
579 conv = build_conv (PMEM_CONV, from, conv);
580 }
581 else if (!same_type_p (fbase, tbase))
582 return NULL;
583 }
584 else if (IS_AGGR_TYPE (TREE_TYPE (from))
585 && IS_AGGR_TYPE (TREE_TYPE (to))
586 /* [conv.ptr]
587
588 An rvalue of type "pointer to cv D," where D is a
589 class type, can be converted to an rvalue of type
590 "pointer to cv B," where B is a base class (clause
591 _class.derived_) of D. If B is an inaccessible
592 (clause _class.access_) or ambiguous
593 (_class.member.lookup_) base class of D, a program
594 that necessitates this conversion is ill-formed. */
595 /* Therefore, we use DERIVED_FROM_P, and not
596 ACESSIBLY_UNIQUELY_DERIVED_FROM_P, in this test. */
597 && DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from)))
598 {
599 from =
600 cp_build_qualified_type (TREE_TYPE (to),
601 cp_type_quals (TREE_TYPE (from)));
602 from = build_pointer_type (from);
603 conv = build_conv (PTR_CONV, from, conv);
604 }
605
606 if (tcode == POINTER_TYPE)
607 {
608 to_pointee = TREE_TYPE (to);
609 from_pointee = TREE_TYPE (from);
610 }
611 else
612 {
613 to_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (to);
614 from_pointee = TYPE_PTRMEM_POINTED_TO_TYPE (from);
615 }
616
617 if (same_type_p (from, to))
618 /* OK */ ;
619 else if (comp_ptr_ttypes (to_pointee, from_pointee))
620 conv = build_conv (QUAL_CONV, to, conv);
621 else if (expr && string_conv_p (to, expr, 0))
622 /* converting from string constant to char *. */
623 conv = build_conv (QUAL_CONV, to, conv);
624 else if (ptr_reasonably_similar (to_pointee, from_pointee))
625 {
626 conv = build_conv (PTR_CONV, to, conv);
627 ICS_BAD_FLAG (conv) = 1;
628 }
629 else
630 return 0;
631
632 from = to;
633 }
同样在【 3 】条文 4.10 “指针转换”中,有以下段落。并注意到在函数的 499 行把左值转换为右值,上面的 conv 保存了这个转换。
1. 一个空指针常量是一个整型常量表达式( 5.19 )的右值,它被评估为整形值 0 。一个空指针常量可以被转换到一个指针类型;其结果是这个类型的空指针值,并且可以与其它指向对象或指向函数的指针值区分开来。 2 个相同类型的空指针值应该是相等的。一个空指针常量到 cv- 限定类型指针的转换是单个转换,而不是一个包含指针转换再加上限定转换( 4.4 )的转换序列。 2. 类型“ pointer to cv T ”,其中 T 是一个对象类型,的一个右值,可以被转换到类型“ pointer to cv void ”的一个右值。其结果指向类型 T 的对象所在内存位置的开头,仿佛该对象是类型 T 作为最后派生类的对象( most derived object (1.8) of type T )(即,不是作为基类子对象)。 3. 类型“ pointer to cv D ”,其中 D 是一个类类型,的一个右值,可以被转换到类型“ pointer to cv B ”,其中 B 是 D 的一个基类(条文 10 ),的一个右值。如果 B 是 D 的一个不可访问(条文 11 )或有二义性( 10.2 )的基类,必须这个转换的程序是非法的。转换的结果是指向派生类对象的基类子对象的指针。空指针值被转换为目标类型的空指针值。 |
条款 1 由上面 526 行代码实现。它是单个 STD_CONV 。而条款 2 的条件由 558 ~ 560 行的代码来测试。 584 ~ 597 行的条件则实现条款 3 。
条文 4.11 “成员指针的转换”显示如下。
1. 一个空指针常量( 4.10 )可以被转换到成员指针;其结果是这个类型的空成员指针值,它与其它从非空指针常量构建的成员指针区分开来。两个相同类型的空成员指针应该是相等的。从一个空指针常量到具有 cv- 限定类型的成员指针的转换是单个转换,而不是包含成员指针转换,及限定转换( 4.4 )的转换序列。 2. 类型“ pointer to member of B of type cv T ”,其中 B 是一个类类型,的一个右值,可以被转换到类型“ pointer to member of D of type cv T ”,其中 D 是 B 的派生类(条文 10 ),的一个右值。如果 B 是 D 的一个不可访问(条文 11 ),或有二义性( 10.2 )或虚拟( 10.1 )的基类,必须这个转换的程序是非法的。转换的结果指向相同的成员,就像转换发生前的成员指针,不过它指向基类的成员,就好像它是派生类的一个成员。该结果指向 D 实例中 B 的成员。因为结果具有类型“ pointer to member of D of type cv T ”,它可以通过一个 D 对象解引用( dereference )。其结果相当于 B 的成员指针被 D 中 B 的子对象解引用。空成员指针值被转换到目标类型的空成员指针值。 [ 成员指针转换的规则(从基类成员指针到派生类成员指针)看起来与指向对象指针的规则相反(从派生类指针到基类指针)( 4.10 ,条文 10 )。为了确保类型安全,这个转换是必要的。注意到一个成员指针不是一个对象指针或函数指针,并且这些指针的转换规则不适用于成员指针。特别的,一个成员指针不能被转换到一个 void* 。 ] |
同样条款 1 被上面 526 行的代码所覆盖。而条款 2 由 567 行的代码块所处理。来到 617 行,经过上面的转换序列,现在 from 及 to 应该或者是相同的类型,或者仅是 cv- 限定符的不同;否则,意味着没有可用的转换。
下面方法指针之间的转换类似于成员指针之间的转换。注意到 fromfn 及 tofn 分别是所指向的函数; fbase 及 tbase 是各自的隐含的 this 指针。因此能执行的转换是:类型“ pointer to method of B of type cv T ”,其中 B 是一个类类型,的一个右值,可用被转换到类型“ pointer to the same method of D of type cv T ”,其中 D 是 B 的一个派生类,的一个右值。并且看到在这里“相同”的含义要比重载中更严格些。
standard_conversion (continue)
634 else if (TYPE_PTRMEMFUNC_P (to) && TYPE_PTRMEMFUNC_P (from))
635 {
636 tree fromfn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from));
637 tree tofn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to));
638 tree fbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fromfn)));
639 tree tbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (tofn)));
640
641 if (!DERIVED_FROM_P (fbase, tbase)
642 || !same_type_p (TREE_TYPE (fromfn), TREE_TYPE (tofn))
643 || !compparms (TREE_CHAIN (TYPE_ARG_TYPES (fromfn)),
644 TREE_CHAIN (TYPE_ARG_TYPES (tofn)))
645 || cp_type_quals (fbase) != cp_type_quals (tbase))
646 return 0;
647
648 from = cp_build_qualified_type (tbase, cp_type_quals (fbase));
649 from = build_method_type_directly (from,
650 TREE_TYPE (fromfn),
651 TREE_CHAIN (TYPE_ARG_TYPES (fromfn)));
652 from = build_ptrmemfunc_type (build_pointer_type (from));
653 conv = build_conv (PMEM_CONV, from, conv);
654 }
【 3 】条文 4.12 “布尔型转换”对以下的转换给出了指引。
1. 算术类型,枚举类型,指针类型,或成员指针类型的一个右值可以被转换为一个布尔类型的右值。一个 0 值,空指针值,或空成员指针值被转换为 false ;其他值被转换为 true 。 |
不过,指针到布尔值的转换等级不如整数到布尔值的转换。
standard_conversion (continue)
655 else if (tcode == BOOLEAN_TYPE)
656 {
657 /* [conv.bool]
658
659 An rvalue of arithmetic, enumeration, pointer, or pointer to
660 member type can be converted to an rvalue of type bool. */
661 if (ARITHMETIC_TYPE_P (from)
662 || fcode == ENUMERAL_TYPE
663 || fcode == POINTER_TYPE
664 || TYPE_PTR_TO_MEMBER_P (from))
665 {
666 conv = build_conv (STD_CONV, to, conv);
667 if (fcode == POINTER_TYPE
668 || TYPE_PTRMEM_P (from)
669 || (TYPE_PTRMEMFUNC_P (from)
670 && ICS_STD_RANK (conv) < PBOOL_RANK))
671 ICS_STD_RANK (conv) = PBOOL_RANK;
672 return conv;
673 }
674
675 return NULL_TREE;
676 }
那么下面的代码处理由【 3 】,条文 4.5 “整型提升”, 4.6 “浮点型提升”, 4.7 “整型转换”, 4.8 “浮点型转换”,及 4.9 “浮点整型转换”所描述的转换。下面的段落是其细节。
1. 类型 char , signed char , unsigned char , short int ,或 unsigned short int 的一个右值可以被转换为类型 int 的一个右值,如果 int 可以表示源类型的所有值;否则,源右值可以被转换为类型 unsigned int 的一个右值。 2. 类型 wchar_t ( 3.9.1 )或枚举类型( 7.2 )的一个右值可以被转换为以下类型中第一个可以表示源类型所有值的类型的一个右值: int , unsigned int , long ,或 unsigned long 。 3. 一个整型位域( 9.6 )的右值可以被转换为类型 int 的一个右值,如果 int 可以表示该位域的所有值;否则,它可以被转换为类型 unsigned int ,如果 unsigned int 可以表示其所有值。如果位域还要大,不会对其应用整型提升。如果该位域具有枚举的类型,出于提升的目的,它亦被视为该类型的其他值。 4. 类型 bool 的一个右值可以被转换为类型 int 的一个右值, false 成为 0 而 true 成为 1 。 5. 这些转换被称为整型提升( integral promotion )。 |
1. 类型 float 的一个右值可以被转换为类型 double 的一个右值。其值不变。 2. 这个转换被称为浮点提升( floating point promotion )。 |
1. 一个整型的右值可以被转换为另一个整型的右值。一个枚举类型的右值可以被转换为一个整型的右值。 2. 如果目标类型是无符号的,其结果值是与源整数同余的( congruent )最小无符号整数。(模 2n ,其中 n 是用于表示该无符号类型的比特数)。 [ 注意:在一个 2 进制补码表示中,这个转换只是概念上的,位模式( bit pattern )没有变化(如果没有发生截断)。 ] 3. 如果目标类型是有符号的,值不会改变,如果目标类型(及位域宽度)能表示它;否则,其值取决于编译器实现。 4. 如果目标类型是 bool ,参见 4.12 。如果源类型是 bool ,值 false 被转换为 0 ,值 true 被转换为 1 。 5. 整形提升不包括在整形转换中。 |
1. 一个浮点类型的右值可以被转换到另一个浮点类型的右值。如果源值可以被目标类型精确表示,转换的结果就是这个精确表示。如果源值位于目标类型所能表示的 2 个相邻值之间,转换的结果依赖于编译器实现对两者的选择。否则,其行为是未定义的。 2. 浮点提升不包括在浮点转换中。 |
1. 一个浮点类型的右值可以被转换为一个整形的右值。该转换就是截断;即,小数部分被舍弃。如果截断后的值不能被目标类型表示,其行为是未定义的。 [ 注意:如果目标类型是 bool ,参见 4.12 。 ] 2. 一个整形或枚举类型的右值可以被转换为一个浮点类型的右值。如果可能,其结果是精确的。否则,依赖于编译器的实现,选择次高或次低的表示值。 [ 注意:如果该整数不能被该浮点类型的一个值精确表示,会发生精度丢失 ] 。如果源类型是 bool ,值 false 被转换为 0 而值 true 转换为 1 。 |
679 到 690 行的代码覆盖了上面所提及的所有的情形。因为 PROMO_RANK 要优于 STD_RANK ,编译器总是尽可能使用 PROMO_RANK 。
standard_conversion (continue)
677 /* We don't check for ENUMERAL_TYPE here because there are no standard
678 conversions to enum type. */
679 else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
680 || tcode == REAL_TYPE)
681 {
682 if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE))
683 return 0;
684 conv = build_conv (STD_CONV, to, conv);
685
686 /* Give this a better rank if it's a promotion. */
687 if (same_type_p (to, type_promotes_to (from))
688 && ICS_STD_RANK (TREE_OPERAND (conv, 0)) <= PROMO_RANK)
689 ICS_STD_RANK (conv) = PROMO_RANK;
690 }
691 else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE
692 && ((*targetm .vector_opaque_p) (from)
693 || (*targetm .vector_opaque_p) (to)))
694 return build_conv (STD_CONV, to, conv);
695 else if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE)
696 && IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
697 && is_properly_derived_from (from, to))
698 {
699 if (TREE_CODE (conv) == RVALUE_CONV)
700 conv = TREE_OPERAND (conv, 0);
701 conv = build_conv (BASE_CONV, to, conv);
702 /* The derived-to-base conversion indicates the initialization
703 of a parameter with base type from an object of a derived
704 type. A temporary object is created to hold the result of
705 the conversion. */
706 NEED_TEMPORARY_P (conv) = 1;
707 }
708 else
709 return 0;
710
711 return conv;
712 }
695 到 707 行的代码处理派生类到基类的转换,它由条文“隐式转换序列”的条款 6 所定义。