现在的位置: 首页 > 综合 > 正文

GCC-3.4.6源代码学习笔记(148)

2013年11月01日 ⁄ 综合 ⁄ 共 8137字 ⁄ 字号 评论关闭

5.13.1.1.2.2. 



确定最优

在收集了所有的候选者后,需要挑出可行的候选者(因为收集的时候,我们只考虑了类型,没有别的),并为涉及的转换函数评估等级,以选出最优的候选。下面的代码执行这个处理。

 

build_user_type_conversion_1 (continue)

 

2478

  
candidates = splice_viable
(candidates, pedantic

, &any_viable_p);

2479

  
if (!any_viable_p)

2480

    
return
0;

2481

2482

  
cand = tourney

(candidates);

5.13.1.1.2.2.1.         



挑选可行的候选者

在下面的函数中,其参数
strict_p

被传递入
pedantic

的值,它如果非
0
,就要求编译器对标准所禁止的一切给出警告。回忆如果隐式转换不能奏效,
implicit_conversion


将返回
NULL
;而对于标准所禁止的转换,将设置
ICS_BAD_FLAG
标记。

 

2165

static
struct
z_candidate
*

2166

splice_viable

(struct
z_candidate *cands,                                                           
in
call.c

2167

            
bool strict_p,

2168

            
bool
*any_viable_p)

2169

{

2170

  
struct
z_candidate *viable;

2171

  
struct
z_candidate **last_viable;

2172

  
struct
z_candidate **cand;

2173

2174

  
viable = NULL;

2175

  
last_viable = &viable;

2176

  
*any_viable_p = false;

2177

2178

  
cand = &cands;

2179

  
while
(*cand)

2180

  
{

2181

    
struct
z_candidate *c = *cand;

2182

    
if (strict_p ?
c->viable == 1 : c->viable)

2183

    
{

2184

      
*last_viable = c;

2185

      
*cand = c->next;

2186

      
c

->next
= NULL;

2187

      
last_viable =
&c->next;

2188

      
*any_viable_p = true;

2189

    
}

2190

    
else

2191

      
cand = &c->next;

2192

  
}

2193

2194

  
return
viable ? viable : cands;

2195

}

5.13.1.1.2.2.2.         



选出最优


3
】的条文
13.3.3
.2
“隐式转换序列排名“给出了挑选最优候选者的规则
[over.ics.rank
]


implicit_conversion


通过,首先尝试标准转换及引用绑定,如果失败,才尝试用户定义转换,实现了规则
2
的第一部分。

1. 
13.3

.3.2
基于更好的转换序列与更好的转换之间的关系,定义了隐式转换序列的一个偏序(
partial ordering
)。如果一个隐式转换序列
S1
被这些规则定义为比
S2
更好的转换序列,那么同时
S2
亦是比
S1
更差的转换序列。如果转换序列
S1
不比转换序列
S2
好,也不比它差,就说
S1

S2
是不可区分(
indistinguishable
)的转换序列。

2. 

当比较隐式转换序列的基本形式(如
13.3.3
.1
所定义)时


一个标准转换序列(
13.3.3
.1.1
)是比一个用户定义转换序列或一个省略转换序列更好的转换序列,而


一个用户定义转换序列(
13.3.3
.1.2
)是比一个省略转换序列(
13.3.3.1.3
)更优的转换序列。

3. 

两个具有相同形式的隐式转换序列是不可区分的转换序列,除非适用下面其中任一规则:


标准转换序列
S1
是比标准转换序列
S2
更好的转换序列,如果

— S1

S2
的一个正确的子序列(比较
13.3.3
.1.1
所定义的规范形式的转换序列,不包括任意左值转型(
Lvalue
Transformation

);恒等转换序列被认为是任意非恒等转换序列的一个子序列);否则,

— S1
的等级比
S2
的等级高,或
S1

S2
具有相同的等级,并且根据下面段落的规则是不可区分的;否则,

— S1

S2
仅是它们的限定转换不同,并且分别产生相似的类型
T1

T2

4.4
),而类型
T1

cv-
限定是类型
T2

cv-
限定的一个正确子集,并且
S1
不是不推荐的字符串数组到指针的转换(
4.2
)。

[
例子:

int f(const
int *);

int f(int *);

int i;

int j = f(&i); // Calls f(int *)


例子结束
]
;否则,

— S1

S2
都是引用绑定(
8.5.3
),并且除了最顶层的
cv-
限定词,这些引用的类型都相同,并且由
S2
的援引所初始化的引用的类型,比由
S1
的援引所初始化的引用的类型,具有更多的
cv-
限定。
[
例如:

int f(const
int &);

int f(int &);

int g(const
int &);

int g(int);

int i;

int j = f(i); // Calls f(int &)

int k = g(i); // ambiguous

class
X {

public
:

void f() const
;

void f();

};

void g(const
X& a, X b) {

a.f(); //Calls X::f() const

b.f(); //Calls X::f()

}


例子结束
]


用户定义转换序列
U1
是比另一个用户定义转换序列更好的转换序列,如果它们包含了相同的用户定义转换函数或构造函数,并且如果
U1
的第二标准转换序列优于
U2
的第二标准转换序列。
[
例如:

struct
A {

operator
short();

} a;

int f(int);

int f(float);

int i = f(a); // Calls f(int), because short → int is better than short
→ float.


例子结束
]

4. 

标准转换序列根据它们的等级排序:一个精确匹配(
Exact Match
)优于提升(
Promotion
),提升优于转换。两个具有相同等级的转换序列是不可区分,除非适用以下任一规则:


一个不是指针转换,或成员指针转换,或布尔转换的转换要优于这些转换。


如果类
B
从类
A
直接或间接派生,
B*

A*
的转换优于
B*

void*
的转换,
A*

void*
的转换优于
B*

void*
的转换。


如果类
B
从类
A
直接或间接派生,而类
C

B
直接或间接派生,
C*

B*
的转换优于
C*

A*
的转换,
[
例如:

struct
A {};

struct
B : public
A {};

struct
C : public
B {};

C *pc;

int f(A *);

int f(B *);

int i = f(pc); // Calls f(B *)


例子结束
]


绑定一个具有类型
C
的表达式到一个具有类型“
B&
”的引用,要优于绑定一个具有类型
C
的表达式到一个具有类型“
A&
”的引用,

— A::*

B::*
的转换优于
A::*

C::*
的转换,

— C

B
的转换优于
C

A
的转换,

— B*

A*
的转换优于
C*

A*
的转换,


绑定一个具有类型
B
的表达式到一个具有类型“
A&
”的引用,要优于绑定一个具有类型
C
的表达式到一个具有类型“
A&
”的引用,

— B::*

C::*
的转换优于
A::*

C::*
的转换,并且

— B

A
的转换优于
C

A
的转换。

[
注意:仅在比较一个自用户定义的初始化转换的第二标准转换序列的上下文中,被比较的转换序列将具有不同的源类型(参见
see 13.3.3
);在其他上下文中,源类型必须是相同,而目标类型不同
]

 

5936

static
struct
z_candidate
*

5937

tourney

(struct
z_candidate *candidates)                                                           
in
call.c

5938

{

5939

  
struct
z_candidate *champ = candidates, *challenger;

5940

  
int fate;

5941

  
int
champ_compared_to_predecessor = 0;

5942

5943

  
/*
Walk through the list once, comparing each current champ to the next

5944

    
candidate, knocking out a candidate or two
with each comparison. 
*/

5945

5946

  
for
(challenger = champ->next; challenger; )

5947

  
{

5948

    
fate = joust
(champ, challenger, 0);

5949

    
if (fate == 1)

5950

      
challenger =
challenger->next;

5951

    
else

5952

  
  
{

5953

      
if (fate == 0)

5954

      
{

5955

        
champ =
challenger->next;

5956

        
if (champ == 0)

5957

          
return

0;

5958

        
champ_compared_to_predecessor = 0;

5959

      
}

5960

      
else

5961

      
{

5962

        
champ = challenger;

5963

        
champ_compared_to_predecessor = 1;

5964

      
}

5965

5966

      
challenger =
champ->next;

5967

    
}

5968

  
}

5969

5970

  
/*
Make sure the champ is better than all the candidates it hasn't yet

5971

    
been
compared to. 
*/

5972

5973

  
for
(challenger = candidates;

5974

      
challenger != champ

5975

         
&&
!(champ_compared_to_predecessor && challenger->next == champ);

5976

      
challenger =
challenger->next)

5977

  
{

5978

    
fate = joust
(champ, challenger, 0);

5979

    
if (fate != 1)

5980

      
return

0;

5981

  
}

5982

5983

  
return
champ;

5984

}

 

通过
joust


候选者被一个个比较来选出最佳者,该函数返回
1
如果
champ

是更优的,
-1
如果
challenger

是更优的,或者
0
如果具有二义性。注意到
champ

总是指向列表中的前一个候选者,而
challenger

是紧跟
champ

之后的候选者。看到在
5946
行的
FOR

循环中
champ

总是指向两个中较佳者,如果能确定的话。


5973
行的
FOR

循环中,如果
champ_compared_to_predecessor


0
,那么退出的条件变成:“
challenger != champ

”;否则就变成:“
challenger != champ && challenger->next != champ

”。注意到仅当
challenger

最后一次发现优于
champ

(因而
champ


challenger

更新),并之后没有出现二义性的结果时,
champ_compared_to_predecessor

可以是
1
;而这个标记
0
,仅当最后一次比较的结果是
champ

优于
chanlleger

。因此对于该标记为
1

champ

之前的候选者不需要比较,但当标记为
0
时需要包括之。为什么需要第二个
FOR

循环呢?首先注意到如果找到最佳候选者,最后一次的比较必然不会出现二义性,否则该函数将在
5957
行返回
0
。另外看到如果出现二义性,这两个候选者都被跳过,比较在后面的候选者中重新开始。因此有可能具有二义性的候选者要优于在第一个
FOR

循环中找到的最佳候选者,而这个情形,在第二
FOR

循环中,将被发现为一个错误,并在
5980
行返回
0

在上面看到,被选出的可行候选者的
viable

域是非
0
值。并记得如果该转换不为标准所允许,这个域将保存值
-1
。作为一个快速的挑选,不同的
viable

值显示谁为更优。毫无疑问,标准所允许的转换总是更优胜。

 

5653

static
int

5654

joust

(struct
z_candidate
*cand1, struct
z_candidate *cand2, bool warn)                     
in call.c

5655

{

5656

  
int winner = 0;

5657

  
int i, off1 = 0, off2 = 0,
len;

5658

5659

 
 
/* Candidates that involve bad conversions are
always worse than those

5660

    
that
don't. 
*/

5661

  
if (cand1->viable >
cand2->viable)

5662

    
return
1;

5663

  
if (cand1->viable <
cand2->viable)

5664

    
return
-1;

5665

5666

  
/*
If we have two pseudo-candidates for conversions to the same type,

5667

    
or two
candidates for the same function, arbitrarily pick one. 
*/

5668

  
if (cand1->fn ==
cand2->fn

5669

      
&& (TYPE_P
(cand1->fn) || DECL_P (cand1->fn)))

5670

    
return
1;

5671

5672

  
/*
a viable function F1

5673

    
is
defined to be a better function than another viable function F2 if

5674

    
for
all arguments i, ICSi(F1) is not a worse conversion sequence than

5675

    
ICSi(F2), and then */

5676

5677

  
/*
for some argument j, ICSj(F1) is a better conversion sequence than

5678

    
ICSj(F2) */

5679

5680

  
/*
For comparing static and non-static member functions, we ignore

5681

    
the
implicit object parameter of the non-static function. The

5682

    
standard says to pretend that the static
function has an object

5683

    
parm,
but that won't work with operator overloading. 

*/

5684

  
len = TREE_VEC_LENGTH
(cand1->convs);

5685

  
if (len != TREE_VEC_LENGTH
(cand2->convs))

5686

  
{

5687

    
if (DECL_STATIC_FUNCTION_P
(cand1->fn)

5688

        
&& !
DECL_STATIC_FUNCTION_P (cand2->fn))

5689

      
off2 = 1;

5690

    
else if (!
DECL_STATIC_FUNCTION_P (cand1->fn)

5691

           
&&
DECL_STATIC_FUNCTION_P (cand2->fn))

5692

    
{

5693

      
off1 = 1;

5694

      
--len;

5695

    
}

5696

    
else

5697

      
abort ();

5698

  
}

5699

5700

  
for
(i = 0; i < len; ++i)

5701

  
{

5702

    
tree t1 = TREE_VEC_ELT
(cand1->convs, i+off1);

5703

    
tree t2 = TREE_VEC_ELT
(cand2->convs, i+off2);

5704

    
int comp =

compare_ics


(t1, t2);

5705

5706

    
if (comp != 0)

5707

    
{

5708

      
if (warn_sign_promo

5709

         
&& ICS_RANK
(t1) + ICS_RANK (t2) == STD_RANK + PROMO_RANK

5710

         
&& TREE_CODE (t1) ==
STD_CONV

5711

         
&& TREE_CODE (t2) ==
STD_CONV

5712

         
&& TREE_CODE
(TREE_TYPE (t1)) == INTEGER_TYPE

5713

         
&& TREE_CODE
(TREE_TYPE (t2)) == INTEGER_TYPE

5714

         
&& (TYPE_PRECISION
(TREE_TYPE (t1))

5715

              
== TYPE_PRECISION
(TREE_TYPE (t2)))

5716

         
&& (TREE_UNSIGNED
(TREE_TYPE (TREE_OPERAND (t1, 0)))

5717

         
|| (TREE_CODE
(TREE_TYPE (TREE_OPERAND (t1, 0)))

5718

              
==
ENUMERAL_TYPE)))

5719

      
{

5720

        
tree type = TREE_TYPE
(TREE_OPERAND (t1, 0));

5721

        
tree type1, type2;

5722

   
     
struct
z_candidate *w, *l;

5723

        
if (comp > 0)

5724

          
type1 = TREE_TYPE
(t1), type2 = TREE_TYPE (t2),

5725

             
w = cand1, l =
cand2;

5726

        
else

5727

          
type1 = TREE_TYPE
(t2), type2 = TREE_TYPE (t1),

5728

        
     
w = cand2, l = cand1;

5729

5730

        
if (warn)

5731

        
{

5732

          
warning
("passing `%T' chooses `%T' over `%T'",

5733

                   
type,
type1, type2);

5734

          
warning (" 
in call to `%D'", w->fn);

5735

        
}

5736

     
   
else

5737

          
add_warning (w, l);

5738

      
}

5739

5740

      
if (winner &&
comp != winner)

5741

      
{

5742

        
winner = 0;

5743

        
goto
tweak;

5744

      
}

5745

      
winner = comp;

5746

抱歉!评论已关闭.