5.13.1.1.2.1.2. 添加模板方法
下面的隐式转换的机制将尝试查是否能隐式地调用某个模板转换操作符。这个过程不能被命令行选项“ –fimiplicit-template ”所关闭。因为该模板函数是隐式调用的,它不能直接地指定模板实参;该模板实参只能根据调用实参推导。而那些不能推导出来的,将不被选中。
在调用点上, ctype 是‘ this ’指针的类型, explicit_targs 是显式模板实参; arglist 是提供的实参;而 return_type 则是对于转换操作符而言理想的类型(或者对于普通的模板函数,它是 NULL )。然后 access_path 是访问该函数的类(这里是‘ this ’指针的类型),而 conversion_path 则是定义该函数的类的 binfo 。
2134 static struct z_candidate *
2135 add_template_candidate (struct z_candidate **candidates, tree tmpl, tree ctype, in call.c
2136 tree explicit_targs, tree arglist, tree return_type,
2137 tree access_path, tree conversion_path, int flags,
2138 unification_kind_t strict)
2139 {
2140 return
2141 add_template_candidate_real (candidates, tmpl, ctype,
2142 explicit_targs, arglist, return_type,
2143 access_path, conversion_path,
2144 flags, NULL_TREE, strict);
2145 }
另外,在这里 strict 对于普通模板函数是 DEDUCE_CALL (或者对于转换操作符,则是 DEDUCE_CONV );并且在下面 add_template_candidate_real 的调用中,把 NULL 传给 obj 。
2035 static struct z_candidate*
2036 add_template_candidate_real (struct z_candidate **candidates, tree tmpl, in call.c
2037 tree ctype, tree explicit_targs, tree arglist,
2038 tree return_type, tree access_path,
2039 tree conversion_path, int flags, tree obj,
2040 unification_kind_t strict)
2041 {
2042 int ntparms = DECL_NTPARMS (tmpl);
2043 tree targs = make_tree_vec (ntparms);
2044 tree args_without_in_chrg = arglist;
2045 struct z_candidate *cand;
2046 int i;
2047 tree fn;
2048
2049 /* We don't do deduction on the in-charge parameter, the VTT
2050 parameter or 'this'. */
2051 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl))
2052 args_without_in_chrg = TREE_CHAIN (args_without_in_chrg);
2053
2054 if ((DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (tmpl)
2055 || DECL_BASE_CONSTRUCTOR_P (tmpl))
2056 && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (tmpl)))
2057 args_without_in_chrg = TREE_CHAIN (args_without_in_chrg);
2058
2059 i = fn_type_unification (tmpl, explicit_targs, targs,
2060 args_without_in_chrg,
2061 return_type, strict, -1);
在上面, DECL_NTPARMS 返回 tmpl 的模板形参的个数;相应地, targs 是保存推导出的实参的 vector ;而 args_without_in_chrg ,由其名字所示,将保存除了那些主管参数( in-charge parameter ,即‘ this ’指针, VTT 等)以外的实参。
5.12.4.1.1.2.2.1. 模板实参推导
下面给出了【 3 】的条文 clause 14.8.2 “模板实参推导” [temp.deduct ] 。
1. 当一个函数模板特化被引用时,所有的模板实参必须具有值。这些值可以,或者被显式指定,或者在一些情形下,从使用处推导出来。 [ 例如: void f(Array<dcomplex>& cv, Array<int>& ci) { sort(cv); // call sort(Array<dcomplex>&) sort(ci); // call sort(Array<int>&) } 及 void g(double d) { int i = convert<int>(d); // call convert<int,double>(double) int c = convert<char>(d); // call convert<char,double>(double) } —例子结束 ] 2. 当指定一个显式模板实参列表时,这些模板实参必须与该模板形参列表兼容,并且必须构成下面所描述的一个有效的函数类型;否则类型推导失败。特别地,当就一个给定的函数模板而言,评估一个显式指定的模板实参列表时,要执行以下步骤: — 指定的模板实参必须与模板形参在类型上匹配(也就是,类型,非类型,模板),并且实参个数不能多于形参;否则类型推导失败。 — 非类型实参必须匹配对应非类型模板形参的类型,或者必须能按 14.3.2 所规定的那样转换到对应非类型形参的类型,否则类型推导失败。 — 在函数模板具现的函数类型中,所有对对应模板形参的引用为指定的模板实参所代替。如果在一个模板形参的替代中,或在函数模板的函数类型的替代中导致一个无效类型,类型推导失败。 [ 注意:异常规范中的等效替代( equivalent substitution )仅当该函数具现后才执行,在那一点上,如果替代导致一个无效的类型,程序是非法的 ] 。类型推导出于以下原因可能失败: Ø 尝试构建一个元素类型是 void ,或一个函数类型,或一个引用类型的数组,或者尝试构建一个大小为 0 或负的数组。 [ 例如: template <class T> int f(T[5]); int I = f<int>(0); // invalid array int j = f<void>(0); // invalid array ] Ø 尝试在一个限定名( qualified name )中使用一个非类类型。 [ 例如: template <class T> int f(typename T::B*); int i = f<int>(0); ] Ø 尝试使用一个在一个限定名的限定词部分( qualifier portion )中的类型;该限定名命名了一个类型,该类型不包含这个指定的成员,或者该指定的成员不是一个类型,但期望的却是一个类型。 [ 例如: template <class T> int f(typename T::B*); struct A {}; struct C { int B; }; int i = f<A>(0); int j = f<C>(0); ] Ø 尝试为一个引用类型构建指针。 Ø 尝试为一个引用类型构建引用,或为 void 构建引用。 Ø 尝试构建“ pointer to member of T ”,当 T 不是一个类类型时。 [ 例如: template <class T> int f(int T::*); int i = f<int>(0); ] Ø 尝试在一个模板实参表达式,或在函数声明中使用的表达式中,执行严格非法的转换。 [ 例如: template <class T, T*> int f(int); int i2 = f<int,1>(0); // can’t conv 1 to int* ] Ø 尝试构建一个具有一个 void 类型参数的函数类型。 Ø 尝试构建一个具有 cv- 限定的函数类型。 3. 在这个替代执行后,执行在 8.3.5 中描述的函数形参类型调整。 [ 例如:一个参数类型“ void () (const int, int[5]) ”变成 “ void(*) (int,int*) ” ] [ 注意:在一个函数参数声明中最高层的限定词不会影响该函数类型,但仍然会影响函数内该函数参数变量的类型。—注释结束 ] [ 例如: template <class T> void f(T t); template <class X> void g(const X x); template <class Z> void h(Z, Z*); int main() { f<int>(1); // #1: function type is f(int), t is nonconst f<const int>(1); // #2: function type is f(int), t is const g<int>(1); // #3: function type is g(int), x is const g<const int>(1); // #4: function type is g(int), x is const h<const int>(1,0); // #5: function type is h(int, const int*) } —例子结束 ] [ 注意: f<int>(1) 及 f<const int>(1) 调用不同的函数,尽管这两个被调用的函数具有相同的函数类型。 — 注释结束 ] 4. 作为结果的替代及调整后的函数类型被用作用于模板实参推导的函数模板的类型。当所有的模板实参被推导出来后,所有在非推导上下文中模板形参的使用,被替代为对应的推导出的实参值。如果该替代导致一个非法类型,如上所描述,类型推导失败。 5. 除上文所述,一个无效值的使用并不会导致类型推导失败。 [ 例如:在下面的例子中 1000 被转换到 signed char ,并且导致一个如( 4.7 )所描述的依赖实现定义的值。换而言之,两个模板都被顾及,虽然 1000 ,当被转换到 signed char 时,导致一个依赖实现定义的值。 template <int> int f(int); template <signed char> int f(int); int i1 = f<1>(0); // ambiguous int i2 = f<1000>(0); // ambiguous —例子结束 ] |
如果模板实参推导成功,下面的函数返回 0 。
8893 int
8894 fn_type_unification (tree fn, in pt.c
8895 tree explicit_targs,
8896 tree targs,
8897 tree args,
8898 tree return_type,
8899 unification_kind_t strict,
8900 int len)
8901 {
8902 tree parms;
8903 tree fntype;
8904 int result;
8905
8906 my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
8907
8908 fntype = TREE_TYPE (fn);
8909 if (explicit_targs)
8910 {
8911 /* [temp.deduct]
8912
8913 The specified template arguments must match the template
8914 parameters in kind (i.e., type, nontype, template), and there
8915 must not be more arguments than there are parameters;
8916 otherwise type deduction fails.
8917
8918 Nontype arguments must match the types of the corresponding
8919 nontype template parameters, or must be convertible to the
8920 types of the corresponding nontype parameters as specified in
8921 _temp.arg.nontype_, otherwise type deduction fails.
8922
8923 All references in the function type of the function template
8924 to the corresponding template parameters are replaced by the
8925 specified template argument values. If a substitution in a
8926 template parameter or in the function type of the function
8927 template results in an invalid type, type deduction fails. */
8928 int i;
8929 tree converted_args;
8930 bool incomplete;
8931
8932 if (explicit_targs == error_mark_node)
8933 return 1;
8934
8935 converted_args
8936 = (coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (fn),
8937 explicit_targs, NULL_TREE, tf_none,
8938 /*require_all_arguments=*/ 0));
8939 if (converted_args == error_mark_node)
8940 return 1;
8941
8942 /* Substitute the explicit args into the function type. This is
8943 necessary so that, for instance, explicitly declared function
8944 arguments can match null pointed constants. If we were given
8945 an incomplete set of explicit args, we must not do semantic
8946 processing during substitution as we could create partial
8947 instantiations. */
8948 incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
8949 processing_template_decl += incomplete;
8950 fntype = tsubst (fntype, converted_args, tf_none, NULL_TREE);
8951 processing_template_decl -= incomplete;
8952
8953 if (fntype == error_mark_node)
8954 return 1;
8955
8956 /* Place the explicitly specified arguments in TARGS. */
8957 for (i = NUM_TMPL_ARGS (converted_args); i--;)
8958 TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (converted_args, i);
8959 }
参数 explicit_args 是显式模板实参,例如,通过一个 template-id 来提供。我们已经在前一节看过了 coerce_template_parms 的一个例子,它转换显式模板实参来匹配形参,而其结果返回给 8935 行的 converted_arg 。那么在 8950 行的 tsubst 用转换后的实参替代模板形参。
fn_type_unification (continue)
8961 parms = TYPE_ARG_TYPES (fntype);
8962 /* Never do unification on the 'this' parameter. */
8963 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
8964 parms = TREE_CHAIN (parms);
8965
8966 if (return_type)
8967 {
8968 /* We've been given a return type to match, prepend it. */
8969 parms = tree_cons (NULL_TREE, TREE_TYPE (fntype), parms);
8970 args = tree_cons (NULL_TREE, return_type, args);
8971 if (len >= 0)
8972 ++len;
8973 }
8974
8975 /* We allow incomplete unification without an error message here
8976 because the standard doesn't seem to explicitly prohibit it. Our
8977 callers must be ready to deal with unification failures in any
8978 event. */
8979 result = type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
8980 targs, parms, args, /*subr=*/ 0,
8981 strict, /*allow_incomplete*/ 1, len);
8982
8983 if (result == 0)
8984 /* All is well so far. Now, check:
8985
8986 [temp.deduct]
8987
8988 When all template arguments have been deduced, all uses of
8989 template parameters in nondeduced contexts are replaced with
8990 the corresponding deduced argument values. If the
8991 substitution results in an invalid type, as described above,
8992 type deduction fails. */
8993 if (tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE)
8994 == error_mark_node)
8995 return 1;
8996
8997 return result;
8998 }
记住现在正在处理函数模板。
在下面的函数中, tparms 指向模板形参; targs 是保存将在这里得到的推导后的模板实参的 vector (它可能是空的,如果给出了显式模板实参。它包含转换后的这些实参); xparms 是该转换操作符包含返回类型的参数; xargs 是该转换操作符上的 args_without_in_chrg (也就是调用时用户使用的实参),加上期望的返回类型;并且如果 subr 是 1 ,表示该函数正在被递归调用(来统一一个函数的实参,或一个函数模板的函数形参); allow_incomplete 是 1 ;并且 xlen 是 -1 ,表示在成功返回前,考虑所有形参;否则就是 xparms 的长度,并考虑这些实参。
9113 static int
9114 type_unification_real (tree tparms, in pt.c
9115 tree targs,
9116 tree xparms,
9117 tree xargs,
9118 int subr,
9119 unification_kind_t strict,
9120 int allow_incomplete,
9121 int xlen)
9122 {
9123 tree parm, arg;
9124 int i;
9125 int ntparms = TREE_VEC_LENGTH (tparms);
9126 int sub_strict;
9127 int saw_undeduced = 0;
9128 tree parms, args;
9129 int len;
9130
9131 my_friendly_assert (TREE_CODE (tparms) == TREE_VEC, 289);
9132 my_friendly_assert (xparms == NULL_TREE
9133 || TREE_CODE (xparms) == TREE_LIST, 290);
9134 my_friendly_assert (!xargs || TREE_CODE (xargs) == TREE_LIST, 291);
9135 my_friendly_assert (ntparms > 0, 292);
9136
9137 switch (strict)
9138 {
9139 case DEDUCE_CALL:
9140 sub_strict = (UNIFY_ALLOW_OUTER_LEVEL | UNIFY_ALLOW_MORE_CV_QUAL
9141 | UNIFY_ALLOW_DERIVED);
9142 break ;
9143
9144 case DEDUCE_CONV:
9145 sub_strict = UNIFY_ALLOW_LESS_CV_QUAL;
9146 break ;
9147
9148 case DEDUCE_EXACT:
9149 sub_strict = UNIFY_ALLOW_NONE;
9150 break ;
9151
9152 case DEDUCE_ORDER:
9153 sub_strict = UNIFY_ALLOW_NONE;
9154 break ;
9155
9156 default :
9157 abort ();
9158 }
9159
9160 if (xlen == 0)
9161 return 0;
参数 strict 是以下之一,而 sub_strict 在上面相应设置之:
Ø DEDUCE_CALL :正在从一个函数调用中推导实参,如 [temp.deduct.call] 所示。
Ø DEDUCE_CONV :正在为一个转换函数推导实参,如 [temp.deduct.conv] 所示。
Ø DEDUCE_EXACT :当执行一个如 [temp.explicit] 所示的显式具现时,当确定一个如 [temp.expl.spec] 所示的显式特化时,或当如 [temp.deduct.funcaddr] 所示提取一个函数模板的地址时,推导实参。
Ø DEDUCE_ORDER :当计算如 [temp.func.order] 及 [temp.class.order] 所示的类或函数模板特化的偏序( partial ordering )时,推导实参。
type_unification_real (continue)
9163 again:
9164 parms = xparms;
9165 args = xargs;
9166 len = xlen;
9167
9168 while (parms
9169 && parms != void_list_node
9170 && args
9171 && args != void_list_node)
9172 {
9173 parm = TREE_VALUE (parms);
9174 parms = TREE_CHAIN (parms);
9175 arg = TREE_VALUE (args);
9176 args = TREE_CHAIN (args);
9177
9178 if (arg == error_mark_node)
9179 return 1;
9180 if (arg == unknown_type_node)
9181 /* We can't deduce anything from this, but we might get all the
9182 template args from other function args. */
9183 continue ;
9184
9185 /* Conversions will be performed on a function argument that
9186 corresponds with a function parameter that contains only
9187 non-deducible template parameters and explicitly specified
9188 template parameters. */
9189 if (!uses_template_parms (parm))
9190 {
9191 tree type;
9192
9193 if (!TYPE_P (arg))
9194 type = TREE_TYPE (arg);
9195 else
9196 type = arg;
9197
9198 if (same_type_p (parm, type))
9199 continue ;
9200 if (strict != DEDUCE_EXACT
9201 && can_convert_arg (parm, type, TYPE_P (arg) ? NULL_TREE : arg))
9202 continue ;
9203
9204 return 1;
9205 }
9206
9207 if (!TYPE_P (arg))
9208 {
9209 my_friendly_assert (TREE_TYPE (arg) != NULL_TREE, 293);
9210 if (type_unknown_p (arg))
9211 {
9212 /* [temp.deduct.type] A template-argument can be deduced from
9213 a pointer to function or pointer to member function
9214 argument if the set of overloaded functions does not
9215 contain function templates and at most one of a set of
9216 overloaded functions provides a unique match. */
9217
9218 if (resolve_overloaded_unification
9219 (tparms, targs, parm, arg, strict, sub_strict)
9220 != 0)
9221 return 1;
9222 continue ;
9223 }
9224 arg = TREE_TYPE (arg);
9225 if (arg == error_mark_node)
9226 return 1;
9227 }
9228
9229 {
9230 int arg_strict = sub_strict;
9231
9232 if (!subr)
9233 arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);
9234
9235 if (unify (tparms, targs, parm, arg, arg_strict))
9236 return 1;
9237 }
9238
9239 /* Are we done with the interesting parms? */
9240 if (--len == 0)
9241 goto done;
9242 }
看到如果形参不依赖于模板参数,就查看实参的类型是否能被隐式地转换到形参的类型,就如同普通函数实参匹配所做的那样。然后如果 arg 具有 unknown_type_node 的 TREE_TYPE ,这可能是某种重载的引用 / 指针(参见下面,它可能是类绑定域中的“ &A::f ”或“ &f ”)。因此通过 resolve_overloaded_unification 尝试按重载处理 arg 。注意,已经查找过的方法应该构建了 BASELINK 。
9281 static int
9282 resolve_overloaded_unification (tree tparms, in pt.c
9283 tree targs,
9284 tree parm,
9285 tree arg,
9286 unification_kind_t strict,
9287 int sub_strict)
9288 {
9289 tree tempargs = copy_node (targs);
9290 int good = 0;
9291 bool addr_p;
9292
9293 if (TREE_CODE (arg) == ADDR_EXPR)
9294 {
9295 arg = TREE_OPERAND (arg, 0);
9296 addr_p = true;
9297 }
9298 else
9299 addr_p = false;
9300
9301 if (TREE_CODE (arg) == COMPONENT_REF)
9302 /* Handle `&x' where `x' is some static or non-static member
9303 function name. */
9304 arg = TREE_OPERAND (arg, 1);
9305
9306 if (TREE_CODE (arg) == OFFSET_REF)
9307 arg = TREE_OPERAND (arg, 1);
9308
9309 /* Strip baselink information. */
9310 if (BASELINK_P (arg))
9311 arg = BASELINK_FUNCTIONS (arg);
9312
9313 if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
9314 {
9315 /* If we got some explicit template args, we need to plug them into
9316 the affected templates before we try to unify, in case the
9317 explicit args will completely resolve the templates in question. */
9318
9319 tree expl_subargs = TREE_OPERAND (arg, 1);
9320 arg = TREE_OPERAND (arg, 0);
9321
9322 for (; arg; arg = OVL_NEXT (arg))
9323 {
9324 tree fn = OVL_CURRENT (arg);
9325 tree subargs, elem;
9326
9327 if (TREE_CODE (fn) != TEMPLATE_DECL)
9328 continue ;
9329
9330 subargs = get_bindings_overload (fn, DECL_TEMPLATE_RESULT (fn),
9331 expl_subargs);
9332 if (subargs)
9333 {
9334 elem = tsubst (TREE_TYPE (fn), subargs, tf_none, NULL_TREE);
9335 good += try_one_overload (tparms, targs, tempargs, parm,
9336 elem, strict, sub_strict, addr_p);
9337 }
9338 }
9339 }
9340 else if (TREE_CODE (arg) == OVERLOAD
9341 || TREE_CODE (arg) == FUNCTION_DECL)
9342 {
9343 for (; arg; arg = OVL_NEXT (arg))
9344 good += try_one_overload (tparms, targs, tempargs, parm,
9345 TREE_TYPE (OVL_CURRENT (arg)),
9346 strict, sub_strict, addr_p);
9347 }
9348 else
9349 abort ();
9350
9351 /* [temp.deduct.type] A template-argument can be deduced from a pointer
9352 to function or pointer to member function argument if the set of
9353 overloaded functions does not contain function templates and at most
9354 one of a set of overloaded functions provides a unique match.
9355
9356 So if we found multiple possibilities, we return success but don't
9357 deduce anything. */
9358
9359 if (good == 1)
9360 {
9361 int i = TREE_VEC_LENGTH (targs);
9362 for (; i--; )
9363 if (TREE_VEC_ELT (tempargs, i))
9364 TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (tempargs, i);
9365 }
9366 if (good)
9367 return 0;
9368
9369 return 1;
9370 }
在上面的 9313 ,合法的 arg 应该是函数节点,它或者是 OVERLOAD ,或者是 TEMPLATE_EXPR_ID ,或者是 FUNCTION_DECL 。在 TEMPLATE_EXPR_ID 中,其第一个操作数是该函数模板的 TEMPLATE_DECL 节点;第二个操作数,如果不是 NULL ,就是显式实参的 TREE_VEC 。如果该函数模板是重载的,前端遍历这个重载列表,并尝试找到的每个函数模板。在 9330 行,该函数模板的 TEMPLATE_DECL 节点中的 DECL_TEMPLATE_RESULT 是为该对象构建的 *_DECL ( for object to be created ( 例如, FUNCTION_DECL) 。
10424 static tree
10425 get_bindings_overload (tree fn, tree decl, tree explicit_args) in pt.c
10426 {
10427 return get_bindings_real (fn, decl, explicit_args, 0, DEDUCE_EXACT, -1);
10428 }
现在 fn 是这个 TEMPLATE_DECL ,而 decl 是关联的 FUNCTION_DECL ,连同 explicit_args 指向显式模板实参。注意到对于所进行的推导,这里使用了 DEDUCE_EXACT 。 如果成功,这个函数返回推导后的实参。
10355 static tree
10356 get_bindings_real (tree fn, in pt.c
10357 tree decl,
10358 tree explicit_args,
10359 int check_rettype,
10360 int deduce,
10361 int len)
10362 {
10363 int ntparms = DECL_NTPARMS (fn);
10364 tree targs = make_tree_vec (ntparms);
10365 tree decl_type;
10366 tree decl_arg_types;
10367 int i;
10368
10369 /* Substitute the explicit template arguments into the type of DECL.
10370 The call to fn_type_unification will handle substitution into the
10371 FN. */
10372 decl_type = TREE_TYPE (decl);
10373 if (explicit_args && uses_template_parms (decl_type))
10374 {
10375 tree tmpl;
10376 tree converted_args;
10377
10378 if (DECL_TEMPLATE_INFO (decl))
10379 tmpl = DECL_TI_TEMPLATE (decl);
10380 else
10381 /* We can get here for some invalid specializations. */
10382 return NULL_TREE;
10383
10384 converted_args
10385 = (coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
10386 explicit_args, NULL_TREE,
10387 tf_none, /*require_all_arguments=*/ 0));
10388 if (converted_args == error_mark_node)
10389 return NULL_TREE;
10390
10391 decl_type = tsubst (decl_type, converted_args, tf_none, NULL_TREE);
10392 if (decl_type == error_mark_node)
10393 return NULL_TREE;
10394 }
10395
10396 decl_arg_types = TYPE_ARG_TYPES (decl_type);
10397 /* Never do unification on the 'this' parameter. */
10398 if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
10399 decl_arg_types = TREE_CHAIN (decl_arg_types);
10400
10401 i = fn_type_unification (fn, explicit_args, targs,
10402 decl_arg_types,
10403 (check_rettype || DECL_CONV_FN_P (fn)
10404 ? TREE_TYPE (decl_type) : NULL_TREE),
10405 deduce, len);
10406
10407 if (i != 0)
10408 return NULL_TREE;
10409
10410 return targs;
10411 }
在 10379 行, DECL_TI_TEMPLATE 返回由 decl 具现或特化的 TEMPLATE_DECL 。这个 TEMPLATE_DECL 将是直接父亲( immediate parent ),但不是最泛化模板( the most general template )。例如,在:
template <class T> struct S { template <class U> void f(U); }
‘ S<int>::f<double> ’的 FUNCTION_DECL ,作为其 DECL_TI_TEMPLATE ,具有‘ template <class U> S<int>::f<U> ’。
作为一个特例,对于一个类模板的一个成员友元模板,这个值将不会是一个 TEMPLATE_DECL ,而是一个表示该模板名及提供的显式模板实参的 IDENTIFIER_NODE 或 OVERLOAD 。例如,在:
template <class T> struct S { friend void f<int>(int, double); }
其 DECL_TI_TEMPLATE 将是‘ f ’的 IDENTIFIER_NODE 。