“ SmallObject ”后的符号是:“ : public ThreadingModel<SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> > ”,它们表示了“ SmallObject ”所派生的基类。 class-head 的规则重现如下。
class-head:
class-key identifier [opt] base-clause [opt]
class-key nested-name-specifier identifier base-clause [opt]
class-key nested-name-specifier [opt] template-id base-clause [opt]
如果 nested-name-specifier 出现,下面的变量 nested_name_specifier 将指向其树节点。毫无疑问,它构成了一个上下文,基类在其中应是可见的。那么在下面的 12330 行,如果 nested_name_specifier 不是 null ,它由 push_scope 设置为当前作用域。
cp_parser_class_head (continue)
12317 /* Indicate whether this class was declared as a `class' or as a
12318 `struct'. */
12319 if (TREE_CODE (type) == RECORD_TYPE)
12320 CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);
12321 cp_parser_check_class_key (class_key, type);
12322
12323 /* Enter the scope containing the class; the names of base classes
12324 should be looked up in that context. For example, given:
12325
12326 struct A { struct B {}; struct C; };
12327 struct A::C : B {};
12328
12329 is valid. */
12330 if (nested_name_specifier)
12331 pop_p = push_scope (nested_name_specifier);
12332 /* Now, look for the base-clause. */
12333 token = cp_lexer_peek_token (parser->lexer);
12334 if (token->type == CPP_COLON)
12335 {
12336 tree bases;
12337
12338 /* Get the list of base-classes. */
12339 bases = cp_parser_base_clause (parser);
12340 /* Process them. */
12341 xref_basetypes (type, bases);
12342 }
12343 /* Leave the scope given by the nested-name-specifier. We will
12344 enter the class scope itself while processing the members. */
12345 if (pop_p)
12346 pop_scope (nested_name_specifier);
12347
12348 done:
12349 if (invalid_explicit_specialization_p)
12350 {
12351 end_specialization ();
12352 --parser->num_template_parameter_lists;
12353 }
12354 *attributes_p = attributes;
12355 return type;
12356 }
事实上,由“ : ”开头的部分,根据语法,被称为 base-clause ,它遵守如下的规则:
base-clause:
: base-specifier-list
base-specifier-list:
base-specifier
base-specifier-list , base-specifier
显然,如果 base-specifier-list 包含了多于一个基类描述符( base-specifier ),它对应于多继承。而且这些基类被在下面函数中的变量 bases 串接起来。
12900 static tree
12901 cp_parser_base_clause (cp_parser* parser) in parser.c
12902 {
12903 tree bases = NULL_TREE;
12904
12905 /* Look for the `:' that begins the list. */
12906 cp_parser_require (parser, CPP_COLON, "`:'");
12907
12908 /* Scan the base-specifier-list. */
12909 while (true)
12910 {
12911 cp_token *token;
12912 tree base;
12913
12914 /* Look for the base-specifier. */
12915 base = cp_parser_base_specifier (parser);
12916 /* Add BASE to the front of the list. */
12917 if (base != error_mark_node)
12918 {
12919 TREE_CHAIN (base) = bases;
12920 bases = base;
12921 }
12922 /* Peek at the next token. */
12923 token = cp_lexer_peek_token (parser->lexer);
12924 /* If it's not a comma, then the list is complete. */
12925 if (token->type != CPP_COMMA)
12926 break ;
12927 /* Consume the `,'. */
12928 cp_lexer_consume_token (parser->lexer);
12929 }
12930
12931 /* PARSER->SCOPE may still be non-NULL at this point, if the last
12932 base class had a qualified name. However, the next name that
12933 appears is certainly not qualified. */
12934 parser->scope = NULL_TREE;
12935 parser->qualifying_scope = NULL_TREE;
12936 parser->object_scope = NULL_TREE;
12937
12938 return nreverse (bases);
12939 }
base-specifier 部分描述了从谁及如何派生。因此其规则如下。
base-specifier:
:: [opt] nested-name-specifier [opt] class-name
virtual access-specifier [opt] :: [opt] nested-name-specifier [opt] class-name
access-specifier virtual [opt] :: [opt] nested-name-specifier [opt] class-name
12955 static tree
12956 cp_parser_base_specifier (cp_parser* parser) in parser.c
12957 {
12958 cp_token *token;
12959 bool done = false;
12960 bool virtual_p = false;
12961 bool duplicate_virtual_error_issued_p = false;
12962 bool duplicate_access_error_issued_p = false;
12963 bool class_scope_p, template_p;
12964 tree access = access_default_node;
12965 tree type;
12966
12967 /* Process the optional `virtual' and `access-specifier'. */
12968 while (!done)
12969 {
12970 /* Peek at the next token. */
12971 token = cp_lexer_peek_token (parser->lexer);
12972 /* Process `virtual'. */
12973 switch (token->keyword)
12974 {
12975 case RID_VIRTUAL:
12976 /* If `virtual' appears more than once, issue an error. */
12977 if (virtual_p && !duplicate_virtual_error_issued_p)
12978 {
12979 cp_parser_error (parser,
12980 "`virtual' specified more than once in base-specified");
12981 duplicate_virtual_error_issued_p = true;
12982 }
12983
12984 virtual_p = true;
12985
12986 /* Consume the `virtual' token. */
12987 cp_lexer_consume_token (parser->lexer);
12988
12989 break ;
12990
12991 case RID_PUBLIC:
12992 case RID_PROTECTED:
12993 case RID_PRIVATE:
12994 /* If more than one access specifier appears, issue an
12995 error. */
12996 if (access != access_default_node
12997 && !duplicate_access_error_issued_p)
12998 {
12999 cp_parser_error (parser,
13000 "more than one access specifier in base-specified");
13001 duplicate_access_error_issued_p = true;
13002 }
13003
13004 access = ridpointers [(int) token->keyword];
13005
13006 /* Consume the access-specifier. */
13007 cp_lexer_consume_token (parser->lexer);
13008
13009 break ;
13010
13011 default :
13012 done = true;
13013 break ;
13014 }
13015 }
13016 /* It is not uncommon to see programs mechanically, errouneously, use
13017 the 'typename' keyword to denote (dependent) qualified types
13018 as base classes. */
13019 if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
13020 {
13021 if (!processing_template_decl)
13022 error ("keyword `typename' not allowed outside of templates");
13023 else
13024 error ("keyword `typename' not allowed in this context "
13025 "(the base class is implicitly a type)");
13026 cp_lexer_consume_token (parser->lexer);
13027 }
13028
13029 /* Look for the optional `::' operator. */
13030 cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/ false);
13031 /* Look for the nested-name-specifier. The simplest way to
13032 implement:
13033
13034 [temp.res]
13035
13036 The keyword `typename' is not permitted in a base-specifier or
13037 mem-initializer; in these contexts a qualified name that
13038 depends on a template-parameter is implicitly assumed to be a
13039 type name.
13040
13041 is to pretend that we have seen the `typename' keyword at this
13042 point. */
13043 cp_parser_nested_name_specifier_opt (parser,
13044 /*typename_keyword_p=*/ true,
13045 /*check_dependency_p=*/ true,
13046 /*type_p=*/ true,
13047 /*is_declaration=*/ true);
13048 /* If the base class is given by a qualified name, assume that names
13049 we see are type names or templates, as appropriate. */
13050 class_scope_p = (parser->scope && TYPE_P (parser->scope));
13051 template_p = class_scope_p && cp_parser_optional_template_keyword (parser);
13052
13053 /* Finally, look for the class-name. */
13054 type = cp_parser_class_name (parser,
13055 class_scope_p,
13056 template_p,
13057 /*type_p=*/ true,
13058 /*check_dependency_p=*/ true,
13059 /*class_head_p=*/ false,
13060 /*is_declaration=*/ true);
13061
13062 if (type == error_mark_node)
13063 return error_mark_node;
13064
13065 return finish_base_specifier (TREE_TYPE (type), access, virtual_p);
13066 }
上面, cp_parser_nested_name_specifier_opt 把 parser 的 scope 设置为 nested-name-specifier 如果出现的话,这又相应地影响类名查找的结果。在 13051 行, cp_parser_optional_template_keyword 检查关键字“ template ”是否出现,如果出现并且 nested-name-specifier 表示一个类作用域,它是一个模板名的明示。对于我们例子, template_p 是 false 。类名查找的细节在前面已经给出。
简而言之,类“ ThreadingModel ”已经被声明了,在 8212 行是 cp_parser_template_name 中, cp_parser_lookup_name 返回相应的 TEMPLATE_DECL 。有趣的是,模板实参“ SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> ”又是 template-id 。因此这个名字沿着 cp_parser_enclosed_template_argument_list , cp_parser_template_argument_list , cp_parser_template_argument , cp_parser_id_expression , cp_parser_unqualified_id , cp_parser_template_id ,再一次加入在 8212 行的 cp_parser_template_name ,找出“ SmallObject ”的 TEMPLATE_DECL (因为类的标签已经被处理了),然后在 7899 行的 cp_parser_template_id 中,递归进入 cp_parser_enclosed_template_argument_list 。
5.12.4.2.3.1.1. 内层 template-id
这一次“ ThreadingModel ”是一个 type-id ,由如下调用栈解析: cp_parser_type_id , cp_parser_type_specifier_seq , cp_parser_type_specifier , cp_parser_simple_type_specifier , cp_parser_type_name ,在 11795 行的 cp_parser_class_name 中,同样的 cp_parser_lookup_name 返回对应的 TEMPLATE_DECL ,而在 11812 行的 cp_parser_maybe_treat_template_as_class 从 TEMPLATE_DECL 的 result 域提取对应的 TYPE_DECL 。然后在 cp_parser_type_id 的 10947 行, groktypename 向这个 TYPE_DECL 的 type 域填入相应的 TEMPLATE_TEMPLATE_PARM 。
接下来“ chunkSize ”及“ maxSmallObjectSize ”都是从 assignment-expression 降下来的 id-expression 。它们的 IDENTIFIER_NODE 作为结果返回。那么在 cp_parser_template_id 的 7994 行,因为 template 是 TEMPLATE_DECL , template-id 需要由下面的 finish_template_type 来构建。
cp_parser_template_id
7991 /* Build a representation of the specialization. */
7992 if (TREE_CODE (template) == IDENTIFIER_NODE)
7993 template_id = build_min_nt (TEMPLATE_ID_EXPR, template, arguments);
7994 else if (DECL_CLASS_TEMPLATE_P (template)
7995 || DECL_TEMPLATE_TEMPLATE_PARM_P (template))
7996 template_id
7997 = finish_template_type (template, arguments,
7998 cp_lexer_next_token_is (parser->lexer,
7999 CPP_SCOPE));
这里 arguments 是 tree_vec 形式的模板实参列表。
2222 tree
2223 finish_template_type (tree name, tree args, int entering_scope) in semantics.c
2224 {
2225 tree decl;
2226
2227 decl = lookup_template_class (name, args,
2228 NULL_TREE, NULL_TREE, entering_scope,
2229 tf_error | tf_warning | tf_user);
2230 if (decl != error_mark_node)
2231 decl = TYPE_STUB_DECL (decl);
2232
2233 return decl;
2234 }
同样参数 name 指向的“ SmallObject ”的 TEMPLATE_DECL 显示如下。当类“ SmallObject ”的类标签得到处理后,我们期望看到这样的树,注意到为了不使图太大,最后的参数“ std::size_t maxSmallObjectSize ”没有显示出来,因为我们可以看到几乎相同的参数“ std::size_t chunkSize ”。
( 点此打开 )
图 110 :类标签处理后的 SmallObject
而在这次调用中,参数 in_decl , context 都是 NULL ,而 entering_scope 是 0 。
4133 tree
4134 lookup_template_class (tree d1, in pt.c
4135 tree arglist,
4136 tree in_decl,
4137 tree context,
4138 int entering_scope,
4139 tsubst_flags_t complain)
4140 {
4141 tree template = NULL_TREE, parmlist;
4142 tree t;
4143
4144 timevar_push (TV_NAME_LOOKUP);
4145
4146 if (TREE_CODE (d1) == IDENTIFIER_NODE)
4147 {
4148 if (IDENTIFIER_VALUE (d1)
4149 && DECL_TEMPLATE_TEMPLATE_PARM_P (IDENTIFIER_VALUE (d1)))
4150 template = IDENTIFIER_VALUE (d1);
4151 else
4152 {
4153 if (context)
4154 push_decl_namespace (context);
4155 template = lookup_name (d1, /*prefer_type=*/ 0);
4156 template = maybe_get_template_decl_from_type_decl (template);
4157 if (context)
4158 pop_decl_namespace ();
4159 }
4160 if (template)
4161 context = DECL_CONTEXT (template);
4162 }
4163 else if (TREE_CODE (d1) == TYPE_DECL && IS_AGGR_TYPE (TREE_TYPE (d1)))
4164 {
4165 tree type = TREE_TYPE (d1);
4166
4167 /* If we are declaring a constructor, say A<T>::A<T>, we will get
4168 an implicit typename for the second A. Deal with it. */
4169 if (TREE_CODE (type) == TYPENAME_TYPE && TREE_TYPE (type))
4170 type = TREE_TYPE (type);
4171
4172 if (CLASSTYPE_TEMPLATE_INFO (type))
4173 {
4174 template = CLASSTYPE_TI_TEMPLATE (type);
4175 d1 = DECL_NAME (template);
4176 }
4177 }
4178 else if (TREE_CODE (d1) == ENUMERAL_TYPE
4179 || (TYPE_P (d1) && IS_AGGR_TYPE (d1)))
4180 {
4181 template = TYPE_TI_TEMPLATE (d1);
4182 d1 = DECL_NAME (template);
4183 }
4184 else if (TREE_CODE (d1) == TEMPLATE_DECL
4185 && TREE_CODE (DECL_TEMPLATE_RESULT (d1)) == TYPE_DECL)
4186 {
4187 template = d1;
4188 d1 = DECL_NAME (template);
4189 context = DECL_CONTEXT (template);
4190 }
4191
4192 /* With something like `template <class T> class X class X { ... };'
4193 we could end up with D1 having nothing but an IDENTIFIER_VALUE.
4194 We don't want to do that, but we have to deal with the situation,
4195 so let's give them some syntax errors to chew on instead of a
4196 crash. Alternatively D1 might not be a template type at all. */
4197 if (! template)
4198 {
4199 if (complain & tf_error)
4200 error ("`%T' is not a template", d1);
4201 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
4202 }
4203
4204 if (TREE_CODE (template) != TEMPLATE_DECL
4205 /* Make sure it's a user visible template, if it was named by
4206 the user. */
4207 || ((complain & tf_user) && !DECL_TEMPLATE_PARM_P (template)
4208 && !PRIMARY_TEMPLATE_P (template)))
4209 {
4210 if (complain & tf_error)
4211 {
4212 error ("non-template type `%T' used as a template", d1);
4213 if (in_decl)
4214 cp_error_at ("for template declaration `%D'", in_decl);
4215 }
4216 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
4217 }
4218
4219 complain &= ~tf_user;
上面 template 在 4187 行被更新作“ SmallObject ”的 TEMPLATE_DECL , dl 被更新为相应的 IDENTIFIER_NODE 节点,而 context 则是 NULL 。并且下面的 template_type 被设置为 TEMPLATE_TEMPLATE_PARM 节点;那么在 4271 行的 most_general_template 返回该模板最泛化的声明( most-general declaration ,对于我们的例子,该模板就是最泛化的形式)。遍历上图中的模板实参,得到 parm_depth 为 1 , arg_depth 为 1 ( arglist 就是上图中的 arguments )。
由其名字所显示, arg_depth 对应于该 template-id 实参的深度,而 parm_depth 是对应模板声明参数的深度。两者不相同的例子如下所示:
template <class T> struct S1 {
template <class U> struct S2 {};
};
在 S2 的声明中,实参列表是“ U ”,但其完整的定义(如果定义在 S1 外部)是: template <class T> template <U> struct S1<T>::S2
这正是解析器所期望的!它必须填入缺失的实参“ T ”。不过,我们没有这个麻烦,我们可以跳过它。
lookup_template_class (continue)
4221 if (DECL_TEMPLATE_TEMPLATE_PARM_P (template))
4222 {
…
4259 }
4260 else
4261 {
4262 tree template_type = TREE_TYPE (template);
4263 tree gen_tmpl;
4264 tree type_decl;
4265 tree found = NULL_TREE;
4266 tree *tp;
4267 int arg_depth;
4268 int parm_depth;
4269 int is_partial_instantiation;
4270
4271 gen_tmpl = most_general_template (template);
4272 parmlist = DECL_TEMPLATE_PARMS (gen_tmpl);
4273 parm_depth = TMPL_PARMS_DEPTH (parmlist);
4274 arg_depth = TMPL_ARGS_DEPTH (arglist);
4275
4276 if (arg_depth == 1 && parm_depth > 1)
4277 {
4278 /* We've been given an incomplete set of template arguments.
4279 For example, given:
4280
4281 template <class T> struct S1 {
4282 template <class U> struct S2 {};
4283 template <class U> struct S2<U*> {};
4284 };
4285
4286 we will be called with an ARGLIST of `U*', but the
4287 TEMPLATE will be `template <class T> template
4288 <class U> struct S1<T>::S2'. We must fill in the missing
4289 arguments. */
4290 arglist
4291 = add_outermost_template_args (TYPE_TI_ARGS (TREE_TYPE (template)),
4292 arglist);
4293 arg_depth = TMPL_ARGS_DEPTH (arglist);
4294 }
4295
4296 /* Now we should have enough arguments. */
4297 my_friendly_assert (parm_depth == arg_depth, 0);
4298
4299 /* From here on, we're only interested in the most general
4300 template. */
4301 template = gen_tmpl;
4302
4303 /* Calculate the BOUND_ARGS. These will be the args that are
4304 actually tsubst'd into the definition to create the
4305 instantiation. */
4306 if (parm_depth > 1)
4307 {
…
4344 }
4345 else
4346 arglist
4347 = coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parmlist),
4348 INNERMOST_TEMPLATE_ARGS (arglist),
4349 template,
4350 complain, /*require_all_args=*/ 1);
在适当地加入额外的实参后, arg_depth 应该等于 parm_depth ,而 parm_depth 多 1 的情形表示正在处理类模板的成员。这不是我们的气数。在 4347 行, INNERMOST_TEMPLATE_PARMS 返回在上图 类标签处理后的 SmallObject 中的 TREE_VEC 节点,而 INNERMOST_TEMPLATE_ARGS 返回整个实参列表。
3805 static tree
3806 coerce_template_parms (tree parms, in pt.c
3807 tree args,
3808 tree in_decl,
3809 tsubst_flags_t complain,
3810 int require_all_arguments)
3811 {
3812 int nparms, nargs, i, lost = 0;
3813 tree inner_args;
3814 tree new_args;
3815 tree new_inner_args;
3816
3817 inner_args = INNERMOST_TEMPLATE_ARGS (args);
3818 nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
3819 nparms = TREE_VEC_LENGTH (parms);
3820
3821 if (nargs > nparms
3822 || (nargs < nparms
3823 && require_all_arguments
3824 && TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)) == NULL_TREE))
3825 {
3826 if (complain & tf_error)
3827 {
3828 error ("wrong number of template arguments (%d, should be %d)",
3829 nargs, nparms);
3830
3831 if (in_decl)
3832 cp_error_at ("provided for `%D'", in_decl);
3833 }
3834
3835 return error_mark_node;
3836 }
上面的 3818 行, NUM_TMPL_ARGS 返回向量的 TREE_VEC_LENGTH 。看到在这一步,实参的数目不应该多于参数的数目。对于我们的声明,实参的数目是 3 ,与参数数目相同。现在 nparms 保存着这个数目。
coerce_template_parms (continue)
3838 new_inner_args = make_tree_vec (nparms);
3839 new_args = add_outermost_template_args (args, new_inner_args);
在参数数目多于实参数目的情形下,涉及到缺省实参的使用。这些缺省实参必须通过 add_outermost_template_args 添加进来。
538 static tree
539 add_outermost_template_args (tree args, tree extra_args) in pt.c
540 {
541 tree new_args;
542
543 /* If there are more levels of EXTRA_ARGS than there are ARGS,
544 something very fishy is going on. */
545 my_friendly_assert (TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (extra_args),
546 0);
547
548 /* If *all* the new arguments will be the EXTRA_ARGS, just return
549 them. */
550 if (TMPL_ARGS_DEPTH (args) == TMPL_ARGS_DEPTH (extra_args))
551 return extra_args;
552
553 /* For the moment, we make ARGS look like it contains fewer levels. */
554 TREE_VEC_LENGTH (args) -= TMPL_ARGS_DEPTH (extra_args);
555
556 new_args = add_to_template_args (args, extra_args);
557
558 /* Now, we restore ARGS to its full dimensions. */
559 TREE_VEC_LENGTH (args) += TMPL_ARGS_DEPTH (extra_args);
560
561 return new_args;
562 }
对于没有使用缺省实参的情况, add_outermost_template_args 不作任何事只是把 new_inner_args 返回给 new_args 。现在 parms 是在上图 类标签处理后的 SmallObject 中的 TREE_VEC 节点;因此对于第一个成员, parm 指向下面的节点。
coerce_template_parms (continue)
3840 for (i = 0; i < nparms; i++)
3841 {
3842 tree arg;
3843 tree parm;
3844
3845 /* Get the Ith template parameter. */
3846 parm = TREE_VEC_ELT (parms, i);
3847
3848 /* Calculate the Ith argument. */
3849 if (i < nargs)
3850 arg = TREE_VEC_ELT (inner_args, i);
3851 else if (require_all_arguments)
3852 /* There must be a default arg in this case. */
3853 arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,
3854 complain, in_decl);
3855 else
3856 break ;
3857
3858 my_friendly_assert (arg, 20030727);
3859 if (arg == error_mark_node)
3860 error ("template argument %d is invalid", i + 1);
3861 else
3862 arg = convert_template_argument (TREE_VALUE (parm),
3863 arg, new_args, complain, i,
3864 i n_decl);
3865
3866 if (arg == error_mark_node)
3867 lost++;
3868 TREE_VEC_ELT (new_inner_args, i) = arg;
3869 }
3870
3871 if (lost)
3872 return error_mark_node;
3873
3874 return new_inner_args;
3875 }
在这次调用中,实参 parm 是“ ThreadingModel ”的 TEMPLATE_DECL , arg 也是指向这个节点。上面因为 nargs 与 naprms 相等, arg 从 inner_args 获得。
3636 static tree
3637 convert_template_argument (tree parm, in pt.c
3638 tree arg,
3639 tree args,
3640 tsubst_flags_t complain,
3641 int i,
3642 tree in_decl)
3643 {
3644 tree val;
3645 tree inner_args;
3646 int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
3647
3648 inner_args = INNERMOST_TEMPLATE_ARGS (args);
3649
3650 if (TREE_CODE (arg) == TREE_LIST
3651 && TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)
3652 {
3653 /* The template argument was the name of some
3654 member function. That's usually
3655 invalid, but static members are OK. In any
3656 case, grab the underlying fields/functions
3657 and issue an error later if required. */
3658 arg = TREE_VALUE (arg);
3659 TREE_TYPE (arg) = unknown_type_node;
3660 }
3661
3662 requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;
3663 requires_type = (TREE_CODE (parm) == TYPE_DECL
3664 || requires_tmpl_type);
3665
3666 is_tmpl_type = ((TREE_CODE (arg) == TEMPLATE_DECL
3667 && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
3668 || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
3669 || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE);
3670
3671 if (is_tmpl_type
3672 && (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
3673 || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE))
3674 arg = TYPE_STUB_DECL (arg);
3675
3676 is_type = TYPE_P (arg) || is_tmpl_type;
显然,此处,我们有 requires_tmpl_type ( 1 ), requires_type ( 1 ), is_tmpl_type ( 1 ), is_type ( 1 )。在这些变量中,可以看到 requires_tmpl_type 是 requires_type 的子集,同样的还有 is_tmpl_type 及 is_type 。任何不一致都意味着错误!
convert_template_arguments (continue)
3678 if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF
3679 && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
3680 {
3681 pedwarn ("to refer to a type member of a template parameter, use `typename %E'", arg);
3682
3683 arg = make_typename_type (TREE_OPERAND (arg, 0),
3684 TREE_OPERAND (arg, 1),
3685 complain & tf_error);
3686 is_type = 1;
3687 }
3688 if (is_type != requires_type)
3689 {
3690 if (in_decl)
3691 {
3692 if (complain & tf_error)
3693 {
3694 error ("type/value mismatch at argument %d in template parameter list for `%D'",
3695 i + 1, in_decl);
3696 if (is_type)
3697 error (" expected a constant of type `%T', got `%T'",
3698 TREE_TYPE (parm),
3699 (is_tmpl_type ? DECL_NAME (arg) : arg));
3700 else if (requires_tmpl_type)
3701 error (" expected a class template, got `%E'", arg);
3702 else
3703 error (" expected a type, got `%E'", arg);
3704 }
3705 }
3706 return error_mark_node;
3707 }
3708 if (is_tmpl_type ^ requires_tmpl_type)
3709 {
3710 if (in_decl && (complain & tf_error))
3711 {
3712 error ("type/value mismatch at argument %d in template parameter list for `%D'",
3713 i + 1, in_decl);
3714 if (is_tmpl_type)
3715 error (" expected a type, got `%T'", DECL_NAME (arg));
3716 else
3717 error (" expected a class template, got `%T'", arg);
3718 }
3719 return error_mark_node;
3720 }
3721
3722 if (is_type)
3723 {
3724 if (requires_tmpl_type)
3725 {
3726 if (TREE_CODE (TREE_TYPE (arg)) == UNBOUND_CLASS_TEMPLATE)
3727 /* The number of argument required is not known yet.
3728 Just accept it for now. */
3729 val = TREE_TYPE (arg);
3730 else
3731 {
3732 tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
3733 tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
3734
3735 if (coerce_template_template_parms (parmparm, argparm,
3736 complain, in_decl,
3737 inner_args))
3738 {
3739 val = arg;
3740
3741 /* TEMPLATE_TEMPLATE_PARM node is preferred over
3742 TEMPLATE_DECL. */
3743 if (val != error_mark_node
3744 && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
3745 val = TREE_TYPE (val);
3746 }
3747 else
3748 {
3749 if (in_decl && (complain & tf_error))
3750 {
3751 error ("type/value mismatch at argument %d in template parameter list for `%D'",
3752 i + 1, in_decl);
3753 error (" expected a template of type `%D', got `%D'", parm, arg);
3754 }
3755
3756 val = error_mark_node;
3757 }
3758 }
3759 }
3760 else
3761 val = groktypename (arg);
3762 }
3763 else
3764 {
…
3790 }
3791
3792 return val;
3793 }
5.12.4.2.3.1.1.1. 模板模板实参
因为 parm 及 arg 指向同一个 TEMPALTE_DECL ,那么 parmparm 及 argparm 都指向下图中的 TREE_VEC ,这个节点来自“ ThreadingModel ”的 TEMPLATE_DECL 。
( 点此打开 )
3559 static int
3560 coerce_template_template_parms (tree parm_parms, in pt.c
3561 tree arg_parms,
3562 tsubst_flags_t complain,
3563 tree in_decl,
3564 tree outer_args)
3565 {
3566 int nparms, nargs, i;
3567 tree parm, arg;
3568
3569 my_friendly_assert (TREE_CODE (parm_parms) == TREE_VEC, 0);
3570 my_friendly_assert (TREE_CODE (arg_parms) == TREE_VEC, 0);
3571
3572 nparms = TREE_VEC_LENGTH (parm_parms);
3573 nargs = TREE_VEC_LENGTH (arg_parms);
3574
3575 /* The rule here is opposite of coerce_template_parms. */
3576 if (nargs < nparms
3577 || (nargs > nparms
3578 && TREE_PURPOSE (TREE_VEC_ELT (arg_parms, nparms)) == NULL_TREE))
3579 return 0;
3580
3581 for (i = 0; i < nparms; ++i)
3582 {
3583 parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, i));
3584 arg = TREE_VALUE (TREE_VEC_ELT (arg_parms, i));
3585
3586 if (arg == NULL_TREE || arg == error_mark_node
3587 || parm == NULL_TREE || parm == error_mark_node)
3588 return 0;
3589
3590 if (TREE_CODE (arg) != TREE_CODE (parm))
3591 return 0;
3592
3593 switch (TREE_CODE (parm))
3594 {
3595 case TYPE_DECL:
3596 break ;
3597
3598 case TEMPLATE_DECL:
3599 /* We encounter instantiations of templates like
3600 template <template <template <class> class> class TT>
3601 class C; */
3602 {
3603 tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
3604 tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
3605
3606 if (!coerce_template_template_parms
3607 (parmparm, argparm, complain, in_decl, outer_args))
3608 return 0;
3609 }
3610 break ;
3611
3612 case PARM_DECL:
3613 /* The tsubst call is used to handle cases such as
3614 template <class T, template <T> class TT> class D;
3615 i.e. the parameter list of TT depends on earlier parameters. */
3616 if (!same_type_p
3617 (tsubst (TREE_TYPE (parm), outer_args, complain, in_decl),
3618 TREE_TYPE (arg)))
3619 return 0;
3620 break ;
3621
3622 default :
3623 abort ();
3624 }
3625 }
3626 return 1;
3627 }
类型完全匹配的 parm_parms 及 arg_parms 使得函数返回 1 。这个函数,除了验证模板模板的实参及模板模板的参数之外,还将填入缺省实参。
然后在 coerce_template_arguments 的 3745 行, val 被更新为上图中的 TEMPLATE_TEMPLATE_PARM 节点。并且这个节点接下来被放入 new_inner_args 的第一个成员。
5.12.4.2.3.1.1.2. 非类型实参
对于第二个实参, coerce_template_arguments 的实参 arg 是“ chunkSize ”的 IDENTIFIER_NODE 节点,而 parm 则是在下图中标为红色的 value 所指向的节点。
( 点此打开 )
convert_template_arguments (continue)
3763 else
3764 {
3765 tree t = tsubst (TREE_TYPE (parm), args, complain, in_decl);
3766
3767 if (invalid_nontype_parm_type_p (t, complain))
3768 return error_mark_node;
3769
3770 if (!uses_template_parms (arg) && !uses_template_parms (t))
3771 /* We used to call digest_init here. However, digest_init
3772 will report errors, which we don't want when complain
3773 is zero. More importantly, digest_init will try too
3774 hard to convert things: for example, `0' should not be
3775 converted to pointer type at this point according to
3776 the standard. Accepting this is not merely an
3777 extension, since deciding whether or not these
3778 conversions can occur is part of determining which
3779 function template to call, or whether a given explicit
3780 argument specification is valid. */
3781 val = convert_nontype_argument (t, arg);
3782 else
3783 val = arg;
3784
3785 if (val == NULL_TREE)
3786 val = error_mark_node;
3787 else if (val == error_mark_node && (complain & tf_error))
3788 error ("could not convert template argument `%E' to `%T'",
3789 arg, t);
3790 }
3791
3792 return val;
3793 }
如果参数是依赖类型(实参是其一个实例),或者实参是一个依赖值,不要尝试折叠这个实参。函数 uses_template_parms 可以告诉我们实参 t 是否依赖模板参数。
4795 int
4796 uses_template_parms (tree t) in pt.c
4797 {
4798 bool dependent_p;
4799 int saved_processing_template_decl;
4800
4801 saved_processing_template_decl = processing_template_decl;
4802 if (!saved_processing_template_decl)
4803 processing_template_decl = 1;
4804 if (TYPE_P (t))
4805 dependent_p = dependent_type_p (t);
4806 else if (TREE_CODE (t) == TREE_VEC)
4807 dependent_p = any_dependent_template_arguments_p (t);
4808 else if (TREE_CODE (t) == TREE_LIST)
4809 dependent_p = (uses_template_parms (TREE_VALUE (t))
4810 || uses_template_parms (TREE_CHAIN (t)));
4811 else if (TREE_CODE (t) == TYPE_DECL)
4812 dependent_p = dependent_type_p (TREE_TYPE (t));
4813 else if (DECL_P (t)
4814 || EXPR_P (t)
4815 || TREE_CODE (t) == TEMPLATE_PARM_INDEX
4816 || TREE_CODE (t) == OVERLOAD
4817 || TREE_CODE (t) == BASELINK
4818 || TREE_CODE (t) == IDENTIFIER_NODE
4819 || TREE_CODE_CLASS (TREE_CODE (t)) == 'c')
4820 dependent_p = ( type_dependent_expression_p (t)
4821 || value_dependent_expression_p (t));
4822 else if (t == error_mark_node)
4823 dependent_p = false;
4824 else
4825 abort ();
4826 processing_template_decl = saved_processing_template_decl;
4827
4828 return dependent_p;
4829 }
在我们的例子中, template-id “ ThreadingModel< SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> > ”中“ SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> ”部分的实参“ ThreadingModel ”就是一个依赖于模板参数的例子。