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

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

2013年06月10日 ⁄ 综合 ⁄ 共 10199字 ⁄ 字号 评论关闭

5.13.1.1.2.       



用户定义转换序列

如果标准转换不奏效,在
implicit_conversion



1107

conv

将是
NULL
。它将要看是否有可用的用户定义的转换。这涉及重载解析的过程,【
3
】条文
13.3
“重载解析”,对此定义如下:

1. 

给定一个作为调用实参的表达式列表,及一组在调用上下文中可被调用的候选函数,重载解析是从中选择最佳调用函数的机制。这个最佳函数的选择准则是,参数的个数,实参对候选函数形参类型的匹配程度,对象(对于非静态成员函数)与隐含的对象形参的匹配程度,候选函数的其他某些属性。
[
注意:被重载解析选中的函数不保证在该上下文中是合适的。其他限制,比如函数的可访问性,可以使得在该调用上下文中使用它是非法的。
]

2. 

重载解析在语言
7
个不同的上下文中选择函数:


名字出现在函数调用语法(
function
call syntax

)中的函数(
13.3.1
.1.1
)的调用;


在名字出现在函数调用语法中的一个类对象(
13.3.1
.1.2
)上,调用一个函数调用操作符(
function
call operator

),一个指针到函数(
pointer-to-function
)的转换函数,一个引用到指针的转换函数,或者一个引用到函数(
reference-to-function
)的转换函数;


对一个表达式中的所引用操作数(
13.3.1
.2
)的调用;


调用一个构造函数用于一个类对象的直接初始化(
8.5
)(
13.3.1
.3
);


调用一个用户定义转换用于一个类对象的拷贝初始化(
8.5
)(
13.3.1
.4
);


调用一个转换函数用于从一个类类型的表达式(
13.3.1
.5
)初始化一个非类类型的对象;并且


调用一个转换函数用于到左值的转换,使用过引用(
8.5.3
)可以直接绑定(
13.3.1.6
)。

3. 

每个上下文以自己的方式,定义了一组候选函数,及实参列表。但是,一旦候选函数及实参列表被确定,在所有的情形下最佳函数的选择是相同的:


首先,候选函数的一个子集——那些具有正确参数个数及满足其他特定条件的函数——被选出构成一个可行函数集(
13.3.2
)。


然后,根据每个可行函数匹配每个实参到相应形参所需的隐式转换序列(
13.3.3
.1
),选择最佳可行函数。

4. 

如果最佳可行函数存在并且唯一,重载解析成功并把它产生为结果。否则,重载解析失败并且该调用非法。当重载解析成功时,而最佳可行函数,在这个上下文中不可访问(条文
11
),程序为非法。

在这里我们在“
在名字出现在函数调用语法中的一个类对象(

13.3.1

.1.2

)上,调用一个函数调用操作符(

function call operator

),一个指针到函数(

pointer-to-function

)的转换函数,一个引用到指针的转换函数,或者一个引用到函数(

reference-to-function

)的转换函数;

”这个上下文中。不管怎么说,在所有上下文中解析是一样的。

5.13.1.1.2.1. 



收集候选函数

C++
允许使用者在类里定义转换操作符;另外具有单个参数的,不以“
explicit
”开头的构造函数也可被用作从参数类型转换到该类类型的转换函数。


3
】条文
13.3.3
.1.2
“用户定义转换序列”给出了以下定义。

1. 

一个用户定义转换序列包括一个起始的标准转换序列,然后一个用户定义转换(
12.3
),然后第二个标准转换序列。如果该用户定义转换由一个构造函数指定(
12.3.1
),起始的标准转换序列把源类型转换为该构造函数的参数所要求的类型。如果该用户定义转换由一个转换函数指定(
12.3.2
),起始的标准转换序列把源类型转换为该转换函数的隐含对象参数。

2. 

第二个标准转换序列把该用户定义转换的结果转换为序列的目标类型。因为其初始值是一个隐式转换序列,当为一个用户定义转换序列选择最佳用户定义转换时,应用用于用户定义转换的特殊规则(参见
13.3.3

13.3.3.1
)。

3. 

如果该用户定义转换由一个模板转换函数所指定,这个第二个标准转换序列必须是精确匹配的等级。

4. 

一个类类型的表达式到相同类类型的转换被定为精确匹配等级,而一个类类型的表达式到该类型的一个基类的转换被定为转换等级(
Conversion rank
),尽管事实上,对于这些情形是一个拷贝构造函数被调用(即,一个用户定义转换函数)。

 

2355

static
struct
z_candidate *

2356

build_user_type_conversion_1

(tree totype, tree expr, int flags)                           
in call.c

2357

{

2358

  
struct
z_candidate *candidates, *cand;

2359

  
tree fromtype = TREE_TYPE
(expr);

2360

  
tree ctors = NULL_TREE,
convs = NULL_TREE;

2361

  
tree args = NULL_TREE;

2362

  
bool any_viable_p;

2363

2364

  
/*
We represent conversion within a hierarchy using RVALUE_CONV and

2365

    
BASE_CONV, as specified by [over.best.ics];
these become plain

2366

    
constructor calls, as specified in
[dcl.init]. 
*/

2367

  
my_friendly_assert
(!IS_AGGR_TYPE (fromtype) || !IS_AGGR_TYPE (totype)

2368

                   
||
!DERIVED_FROM_P (totype, fromtype), 20011226);

2369

2370

  
if (IS_AGGR_TYPE (totype))

2371

    
ctors = lookup_fnfields
(TYPE_BINFO (totype),

2372

                        
complete_ctor_identifier

,

2373

                        
0);

2374

2375

  
if (IS_AGGR_TYPE (fromtype))

2376

    
convs = lookup_conversions
(fromtype);

 

因此如果目标类型是类,收集所有定义的构造函数,因为构造函数亦可被用作转换函数。而如果源类型是类,用户定义的转换操作符就被视为候选,它们由下面的函数来收集。

 

2421

tree

2422

lookup_conversions

(tree type)                                                                  
in
search.c

2423

{

2424

  
tree t;

2425

  
tree conversions =
NULL_TREE;

2426

2427

  
complete_type
(type);

2428

  
bfs_walk
(TYPE_BINFO (type), add_conversions
, 0,
&conversions);

2429

2430

  
for
(t = conversions; t; t = TREE_CHAIN (t))

2431

    
IDENTIFIER_MARKED (DECL_NAME (OVL_CURRENT
(TREE_VALUE (t)))) = 0;

2432

2433

  
return
conversions;

2434

}

 


lookup_conversions


中,
bfs_walk


里的
fn


add_conversions


,这个函数总是返回
NULL
从而强制完整的遍历。看到参数
data

被用于保存所有合格的候选者;而对于转换到相同类型的转换操作符,仅记录第一个被找到的。

 

2365

static
tree

2366

add_conversions

(tree binfo, void *data)                                                     
in
search.c

2367

{

2368

  
int i;

2369

  
tree method_vec =
CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));

2370

  
tree *conversions = (tree *)
data;

2371

2372

  
/*
Some builtin types have no method vector, not even an empty one. 
*/

2373

  
if (!method_vec)

2374

    
return
NULL_TREE;

2375

2376

  
for
(i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)

2377

  
{

2378

    
tree tmp = TREE_VEC_ELT
(method_vec, i);

2379

    
tree name;

2380

2381

    
if (!tmp || !
DECL_CONV_FN_P (OVL_CURRENT (tmp)))

2382

      
break
;

2383

2384

    
name = DECL_NAME
(OVL_CURRENT (tmp));

2385

2386

    
/*
Make sure we don't already have this conversion. 
*/

2387

    
if (! IDENTIFIER_MARKED
(name))

2388

    
{

2389

      
tree t;

2390

2391

      
/*
Make sure that we do not already have a conversion

2392

   
     
operator for this type. Merely checking
the NAME is not

2393

   
     
enough because two conversion operators to
the same type

2394

   
     
may not have the same NAME. 

*/

2395

      
for
(t = *conversions; t; t = TREE_CHAIN (t))

2396

      
{

2397

        
tree fn;

2398

        
for
(fn = TREE_VALUE (t); fn; fn = OVL_NEXT (fn))

2399

          
if (same_type_p
(TREE_TYPE (name),

2400

                        
DECL_CONV_FN_TYPE
(OVL_CURRENT (fn))))

2401

            
break
;

2402

        
if (fn)

2403

          
break
;

2404

      
}

2405

      
if (!t)

2406

      
{

2407

        
*conversions =
tree_cons (binfo, tmp, *conversions);

2408

        
IDENTIFIER_MARKED
(name) = 1;

2409

      
}

2410

    
}

2411

  
}

2412

  
return
NULL_TREE;

2413

}

 

在有关成员查找的章节,我们看到已经被查找过的方法会构建有
BASELINK
节点,而对于非静态方法,定义参数应该是隐含的‘
this
’指针,但对于构造函数,‘
this
’指针还没有构建,在该构造函数执行后,它才就位。因此对于构造函数,为这个隐含的参数构建一个为
NULL
的‘
this
’指针。

 

build_user_type_conversion_1 (continue)

 

2378

  
candidates = 0;

2379

  
flags |=
LOOKUP_NO_CONVERSION;

2380

2381

  
if (ctors)

2382

  
{

2383

    
tree t;

2384

2385

    
ctors = BASELINK_FUNCTIONS
(ctors);

2386

2387

    
t = build_int_2
(0, 0);

2388

    
TREE_TYPE (t) = build_pointer_type
(totype);

2389

    
args = build_tree_list
(NULL_TREE, expr);

2390

    
/*
We should never try to call the abstract or base constructor

2391

      
from
here. 
*/

2392

    
my_friendly_assert
(!DECL_HAS_IN_CHARGE_PARM_P (OVL_CURRENT (ctors))

2393

              
       
&& !DECL_HAS_VTT_PARM_P
(OVL_CURRENT (ctors)),

2394

                     
20011226);

2395

    
args = tree_cons
(NULL_TREE, t, args);

2396

  
}

2397

  
for
(; ctors; ctors = OVL_NEXT (ctors))

2398

  
{

2399

    
tree ctor = OVL_CURRENT
(ctors);

2400

    
if (DECL_NONCONVERTING_P
(ctor))

2401

      
continue
;

2402

2403

    
if (TREE_CODE (ctor) ==
TEMPLATE_DECL)

2404

      
cand = add_template_candidate
(&candidates,
ctor, totype,

2405

                               
  
NULL_TREE, args, NULL_TREE,

2406

                                 
TYPE_BINFO
(totype),

2407

                                 
TYPE_BINFO
(totype),

2408

                                 
flags,

2409

                                 
DEDUCE_CALL);

2410

    
else

2411

      
cand = add_function_candidate
(&candidates,
ctor, totype,

2412

                                
args,
TYPE_BINFO (totype),

2413

                                
TYPE_BINFO
(totype),

2414

          
                      
flags);

2415

2416

    
if (cand)

2417

      
cand->second_conv = build1
(IDENTITY_CONV, totype, NULL_TREE);

2418

  
}

5.13.1.1.2.1.1.         



添加普通函数

如果该构造函数可以被作为转换函数使用(
DECL_NONCONVERTING_P
可以分辨),它们都被包括做候选。而记得如果是一个类模板,其构造函数也将是
TEMPLATE_DECL
。这样的节点由
add_template_candidate


来添加。而对于非模板方法,则是调用
add_function_candidate


 

1164

static
struct
z_candidate
*

1165

add_function_candidate

(struct
z_candidate **candidates,                                   
in call.c

1166

                     
tree fn,
tree ctype, tree arglist,

1167

                     
tree
access_path, tree conversion_path,

1168

                     
int
flags)

1169

{

1170

  
tree parmlist =
TYPE_ARG_TYPES (TREE_TYPE (fn));

1171

  
int i, len;

1172

  
tree convs;

1173

  
tree parmnode, argnode;

1174

  
tree orig_arglist;

1175

  
int viable = 1;

1176

1177

 
 
/* Built-in functions that haven't been
declared don't really

1178

    
exist. 

*/

1179

  
if (DECL_ANTICIPATED (fn))

1180

    
return
NULL;

1181

1182

  
/*
The `this', `in_chrg' and VTT arguments to constructors are not

1183

    
considered in overload resolution. 
*/

1184

  
if (DECL_CONSTRUCTOR_P (fn))

1185

  
{

1186

    
parmlist = skip_artificial_parms_for
(fn, parmlist);

1187

    
orig_arglist = arglist;

1188

    
arglist = skip_artificial_parms_for
(fn, arglist);

1189

  
}

1190

  
else

1191

    
orig_arglist = arglist;

1192

1193

  
len = list_length (arglist);

1194

  
convs = make_tree_vec (len);

1195

1196

  
/*
13.3.2 - Viable functions
[over.match.viable]

1197

    
First,
to be a viable function, a candidate function shall have enough

1198

    
parameters to agree in number with the
arguments in the list.

1199

1200

    
We
need to check this first; otherwise, checking the ICSes might cause

1201

    
us to
produce an ill-formed template instantiation. 


*/

1202

1203

  
parmnode = parmlist;

1204

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

1205

  
{

1206

    
if (parmnode == NULL_TREE
|| parmnode == void_list_node)

1207

      
break
;

1208

    
parmnode = TREE_CHAIN
(parmnode);

1209

  
}

1210

1211

  
if (i < len &&
parmnode)

1212

    
viable = 0;

1213

1214

  
/*
Make sure there are default args for the rest of the parms. 
*/

1215

  
else if (!sufficient_parms_p
(parmnode))

1216

    
viable = 0;

1217

1218

  
if (! viable)

1219

    
goto
out;

1220

1221

  
/*
Second, for F to be a viable function, there shall exist for each

1222

    
argument an implicit conversion sequence
that converts that argument

1223

    
to the
corresponding parameter of F. 
*/

1224

1225

  
parmnode = parmlist;

1226

  
argnode = arglist;

 

作为一个候选,必须是一个可行的函数调用。正如我们在前面所见,构造函数可能包括了
1
个以上的“人造”参数,其数目依赖于类的定义(它是否具有
VTT
,虚拟基类等)。

 

1655

tree

1656

lvalue_type

(tree arg)                                                                                       
in
tree.c

1657

{

1658

  
tree type = TREE_TYPE (arg);

1659

  
return
type;

1660

}

 

从函数的角度,参数是左值,它可以在函数体内操纵。上面的
lvalue_type


返回了
arg

的类型,当它被用作一个左值时。很可能实参的类型与对应形参的类型不相同;不过,它们必须能通过隐式转换序列来匹配。

而如果遇到了省略参数(
ellipsis parameter
),执行在
1264
行的
ELSE

块;看到这仍然需要为这个参数构建
IDENTITY_CONV
,不过设置了标记
ICS_ELLIPSIS_FLAG
来表示该
IDENTITY_CONV
用于省略参数。

 

add_function_candidate (continue)

 

1228

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

1229

  
{

1230

    
tree arg = TREE_VALUE
(argnode);

1231

    
tree argtype = lvalue_type
(arg);

1232

    
tree t;

1233

    
int is_this;

1234

1235

    
if (parmnode ==
void_list_node)

1236

      
break
;

1237

1238

    
is_this = (i == 0
&& DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)

1239

            
&& !
DECL_CONSTRUCTOR_P (fn));

1240

1241

    
if (parmnode)

1242

    
{

1243

      
tree parmtype = TREE_VALUE
(parmnode);

1244

1245

      
/*
The type of the implicit object parameter ('this') for

1246

        
overload resolution is not always the
same as for the

1247

        
function itself; conversion functions
are considered to

1248

        
be
members of the class being converted, and functions

1249

        
introduced by a using-declaration are
considered to be

1250

        
members of the class that uses them.

1251

1252

        
Since build_over_call ignores the ICS
for the `this'

1253

        
parameter, we can just change the parm
type. 
*/

1254

      
if (ctype &&
is_this)

1255

      
{

1256

        
parmtype

1257

            
= build_qualified_type
(ctype,

1258

                                
TYPE_QUALS
(TREE_TYPE (parmtype)));

1259

        
parmtype =

build_pointer_type


(parmtype);

1260

      
}

1261

1262

      
t =

implicit_conversion


(parmtype, argtype, arg, flags);

1263

    
}

1264

    
else

1265

    
{

1266

      
t = build1
(IDENTITY_CONV, argtype, arg);

1267

      
ICS_ELLIPSIS_FLAG (t) =
1;

1268

    
}

1269

1270

    
if (t && is_this)

1271

      
ICS_THIS_FLAG (t) = 1;

1272

1273

    
TREE_VEC_ELT (convs, i) =
t;

1274

    
if (! t)

1275

    
{

1276

      
viable = 0;

1277

      
break
;

抱歉!评论已关闭.