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 。