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

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 ;

1278      }

1279

1280      if (ICS_BAD_FLAG (t))

1281        viable = -1;

1282

1283      if (parmnode)

1284        parmnode = TREE_CHAIN (parmnode);

1285      argnode = TREE_CHAIN (argnode);

1286    }

1287

1288   out:

1289    return add_candidate (candidates, fn, orig_arglist, convs, access_path,

1290                      conversion_path, viable);

1291 }

 

所有的候选者都被连在一个链表中,这个链表的节点的类型是 z_candidate ,它用于保存相关的信息。

 

312    struct z_candidate GTY(()) {                                                                           in call.c

313      /* The FUNCTION_DECL that will be called if this candidate is

314        selected by overload resolution.  */

315      tree fn;

316      /* The arguments to use when calling this function.  */

317      tree args;

318      /* The implicit conversion sequences for each of the arguments to

319        FN.  */

320      tree convs;

321      /* If FN is a user-defined conversion, the standard conversion

322        sequence from the type returned by FN to the desired destination

323        type.  */

324      tree second_conv;

325      int viable;

326      /* If FN is a member function, the binfo indicating the path used to

327        qualify the name of FN at the call site. This path is used to

328        determine whether or not FN is accessible if it is selected by

329        overload resolution. The DECL_CONTEXT of FN will always be a

330        (possibly improper) base of this binfo.  */

331      tree access_path;

332      /* If FN is a non-static member function, the binfo indicating the

333        subobject to which the `this' pointer should be converted if FN

334        is selected by overload resolution. The type pointed to the by

335        the `this' pointer must correspond to the most derived class

336        indicated by the CONVERSION_PATH.  */

337      tree conversion_path;

338      tree template;

339      tree warnings;

340      struct z_candidate *next;

341    };

 

注意传入的 conversion_path access_path ,对于构造函数,它们都是目标类的 binfo

 

1138 static struct z_candidate *

1139 add_candidate (struct z_candidate **candidates,                                                 in call.c

1140               tree fn, tree args, tree convs, tree access_path,

1141               tree conversion_path, int viable)

1142 {

1143    struct z_candidate *cand = ggc_alloc_cleared (sizeof (struct z_candidate));

1144

1145    cand->fn = fn;

1146    cand->args = args;

1147    cand->convs = convs;

1148    cand->access_path = access_path;

1149    cand->conversion_path = conversion_path;

1150    cand->viable = viable;

1151    cand->next = *candidates;

1152    *candidates = cand;

1153

1154    return cand;

1155 }

 

对于构造函数以外的转换操作符,看到传入 add_function_candidate conversion_path 是在 2426 行得到的 binfo ,它是在 add_conversions 2407 行设置的,它是定义了该方法的类的 binfo

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值