我们已经看过了解析器处理类模板“ SingleThreaded ”的过程,不过这个例子作为模板声明来说相当简单。接下来,我们来看一个从“ SingleThreaded ”派生来的模板声明,它能启示我们前端是如何处理模板模板参数及继承关系。下面是我们将要处理的 class-head :
template
<
template <class > class ThreadingModel = DEFAULT_THREADING,
std ::size_t chunkSize = DEFAULT_CHUNK_SIZE,
std ::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE
>
class SmallObject : public ThreadingModel<
SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> >
其中, DEFAULT_THREADING 是“ ::Loki::SingleThreaded ”的别名。该声明遵循以下规则:
template-declaration:
export [opt] template-parameter-list-seq decl-specifier-seq [opt] init-declarator [opt] ;
如同前一个例子,经受如下调用栈 cp_parser_template_declaration à cp_parser_template_declaration_after_export à begin_template_parm_list (插入作用域 sk_template_parms ), cp_parser_template_parameter_list à cp_parser_template_parameter à cp_parser_type_parameter ,该声明运行以下 cp_parser_type_parameter 的代码。
7720 static tree
7721 cp_parser_type_parameter (cp_parser* parser) in parser.c
7722 {
7723 cp_token *token;
7724 tree parameter;
7725
7726 /* Look for a keyword to tell us what kind of parameter this is. */
7727 token = cp_parser_require (parser, CPP_KEYWORD,
7728 "`class', `typename', or `template'");
7729 if (!token)
7730 return error_mark_node;
7731
7732 switch (token->keyword)
7733 {
7734 case RID_CLASS:
7735 case RID_TYPENAME:
7736 {
...
7764 }
7765 break ;
7766
7767 case RID_TEMPLATE:
7768 {
7769 tree parameter_list;
7770 tree identifier;
7771 tree default_argument;
7772
7773 /* Look for the `<'. */
7774 cp_parser_require (parser, CPP_LESS, "`<'");
7775 /* Parse the template-parameter-list. */
7776 begin_template_parm_list ();
7777 parameter_list
7778 = cp_parser_template_parameter_list (parser);
7779 parameter_list = end_template_parm_list (parameter_list);
我们例子的第一个模板参数是以关键字 template 开头的模板模板参数。这个关键字 template 使得事情变得有趣——一个额外的 sk_template_parms 作用域被加入,我们将得到如下的结构。
图 96 :处理模板模板参数之前
对于这个模板模板参数,它本身也是一个模板声明。这里在这个例子中,这个模板模板参数是:“ template <class> class ThreadingModel ”,现在开头的“ template < ”被解析器消化掉了。因此在 cp_parser_template_parameter (由 7778 行的 cp_parser_template_parameter_list 调用)中,以下代码将为下一个进入的符号“ class ”所执行。
7654 static tree
7655 cp_parser_template_parameter (cp_parser* parser) in parser.c
7656 {
7657 cp_token *token;
7658
7659 /* Peek at the next token. */
7660 token = cp_lexer_peek_token (parser->lexer);
7661 /* If it is `class' or `template', we have a type-parameter. */
7662 if (token->keyword == RID_TEMPLATE)
7663 return cp_parser_type_parameter (parser);
7664 /* If it is `class' or `typename' we do not know yet whether it is a
7665 type parameter or a non-type parameter. Consider:
7666
7667 template <typename T, typename T::X X> ...
7668
7669 or:
7670
7671 template <class C, class D*> ...
7672
7673 Here, the first parameter is a type parameter, and the second is
7674 a non-type parameter. We can tell by looking at the token after
7675 the identifier -- if it is a `,', `=', or `>' then we have a type
7676 parameter. */
7677 if (token->keyword == RID_TYPENAME || token->keyword == RID_CLASS)
7678 {
7679 /* Peek at the token after `class' or `typename'. */
7680 token = cp_lexer_peek_nth_token (parser->lexer, 2);
7681 /* If it's an identifier, skip it. */
7682 if (token->type == CPP_NAME)
7683 token = cp_lexer_peek_nth_token (parser->lexer, 3);
7684 /* Now, see if the token looks like the end of a template
7685 parameter. */
7686 if (token->type == CPP_COMMA
7687 || token->type == CPP_EQ
7688 || token->type == CPP_GREATER)
7689 return cp_parser_type_parameter (parser);
7690 }
…
7703 }
显然,“ <class> ”部分是该模板模板参数声明中的模板参数;这听起来怪怪的,但正反映了 C++ 的功能强大。模板可以嵌套至深的层次——标准规定至少要允许 12 层,事实上,商业编译器都允许不少于 128 层的嵌套。
对于这个模板参数“ <class> ”, cp_parser_type_parameter 被递归调用。
7720 static tree
7721 cp_parser_type_parameter (cp_parser* parser) in parser.c
7722 {
7723 cp_token *token;
7724 tree parameter;
7725
7726 /* Look for a keyword to tell us what kind of parameter this is. */
7727 token = cp_parser_require (parser, CPP_KEYWORD,
7728 "`class', `typename', or `template'");
7729 if (!token)
7730 return error_mark_node;
7731
7732 switch (token->keyword)
7733 {
7734 case RID_CLASS:
7735 case RID_TYPENAME:
7736 {
7737 tree identifier;
7738 tree default_argument;
7739
7740 /* If the next token is an identifier, then it names the
7741 parameter. */
7742 if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
7743 identifier = cp_parser_identifier (parser);
7744 else
7745 identifier = NULL_TREE;
7746
7747 /* Create the parameter. */
7748 parameter = finish_template_type_parm (class_type_node, identifier);
7749
7750 /* If the next token is an `=', we have a default argument. */
7751 if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
7752 {
...
7757 }
7758 else
7759 default_argument = NULL_TREE;
7760
7761 /* Create the combined representation of the parameter and the
7762 default argument. */
7763 parameter = build_tree_list (default_argument, parameter);
7764 }
7765 break ;
…
7848 }
7849
7850 return parameter;
7851 }
上面的 finish_template_type_parm 为该参数构建了 tree_list 节点;并且在 7763 行将其整合入另一个 tree_list 节点。那么 parameter 指向如下的节点,因为该参数是匿名而且没有缺省参数。
图 97 :模板模板参数的节点
回到 cp_parser_template_parameter_list , process_template_parm 打包模板的参数。注意到这是模板模板参数声明的模板参数!参数 next 指向上图中的 parameter 节点。
2161 tree
2162 process_template_parm (tree list, tree next) in pt.c
2163 {
2164 tree parm;
2165 tree decl = 0;
2166 tree defval;
2167 int is_type, idx;
2168
2169 parm = next;
2170 my_friendly_assert (TREE_CODE (parm) == TREE_LIST, 259);
2171 defval = TREE_PURPOSE (parm);
2172 parm = TREE_VALUE (parm);
2173 is_type = TREE_PURPOSE (parm) == class_type_node;
2174
2175 if (list)
2176 {
…
2184 }
2185 else
2186 idx = 0;
2187
2188 if (!is_type)
2189 {
…
2212 }
2213 else
2214 {
2215 tree t;
2216 parm = TREE_VALUE (parm);
2217
2218 if (parm && TREE_CODE (parm) == TEMPLATE_DECL)
2219 {
...
2226 }
2227 else
2228 {
2229 t = make_aggr_type (TEMPLATE_TYPE_PARM);
2230 /* parm is either IDENTIFIER_NODE or NULL_TREE. */
2231 decl = build_decl (TYPE_DECL, parm, t);
2232 }
2233
2234 TYPE_NAME (t) = decl;
2235 TYPE_STUB_DECL (t) = decl;
2236 parm = decl;
2237 TEMPLATE_TYPE_PARM_INDEX (t)
2238 = build_template_parm_index (idx, processing_template_decl ,
2239 processing_template_decl ,
2240 decl, TREE_TYPE (parm));
2241 }
2242 DECL_ARTIFICIAL (decl) = 1;
2243 SET_DECL_TEMPLATE_PARM_P (decl);
2244 pushdecl (decl);
2245 parm = build_tree_list (defval, parm);
2246 return chainon (list, parm);
2247 }
此处, begin_template_parm_list 目前已经被调用了 2 次,所以 processing_template_decl 是 2 。注意到 TEMPLATE_TPYE_PARM 的 TYPE_DECL 是匿名的,因此在下面的 pushdecl 中,这个 TYPE_DECL ,通过 add_decl_to_level ,被链入相关 cxx_scope 对象的 names 域。
566 tree
567 pushdecl (tree x) in name-lookup.c
568 {
569 tree t;
570 tree name;
571 int need_new_binding;
572
573 timevar_push (TV_NAME_LOOKUP);
574
575 need_new_binding = 1;
576
577 if (DECL_TEMPLATE_PARM_P (x))
578 /* Template parameters have no context; they are not X::T even
579 when declared within a class or namespace. */
580 ;
581 else
582 {
…
602 }
603
604 name = DECL_NAME (x);
605 if (name)
606 {
…
1007 }
1008
1009 if (need_new_binding)
1010 add_decl_to_level (x,
1011 DECL_NAMESPACE_SCOPE_P (x)
1012 ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
1013 : current_binding_level);
1014
1015 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);
1016 }
那么从 cp_parser_template_parameter_list 回到外面的 cp_parser_type_parameter , end_template_parm_list 接下来准备 current_template_parms 。而返回的 parameter_list 就如下图。
( 点此打开 )
图 98 :模板模板参数声明中的模板参数列表
下一个符号必须是“ > class identifier [opt] ”。由这些符号,这个模板模板参数开始形成。
cp_parser_type_parameter (continue)
7780 /* Look for the `>'. */
7781 cp_parser_require (parser, CPP_GREATER, "`>'");
7782 /* Look for the `class' keyword. */
7783 cp_parser_require_keyword (parser, RID_CLASS, "`class'");
7784 /* If the next token is an `=', then there is a
7785 default-argument. If the next token is a `>', we are at
7786 the end of the parameter-list. If the next token is a `,',
7787 then we are at the end of this parameter. */
7788 if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
7789 && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER)
7790 && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
7791 {
7792 identifier = cp_parser_identifier (parser);
7793 /* Treat invalid names as if the parameter were nameless. */
7794 if (identifier == error_mark_node)
7795 identifier = NULL_TREE;
7796 }
7797 else
7798 identifier = NULL_TREE;
7799
7800 /* Create the template parameter. */
7801 parameter = finish_template_template_parm (class_type_node ,
7802 identifier);
这个模板模板参数是一个用于模板参数的模板声明,它应该有一个 TEMPLATE_DECL 来代表这个模板声明。
1943 tree
1944 finish_template_template_parm (tree aggr, tree identifier) in semantics.c
1945 {
1946 tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
1947 tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
1948 DECL_TEMPLATE_PARMS (tmpl) = current_template_parms ;
1949 DECL_TEMPLATE_RESULT (tmpl) = decl;
1950 DECL_ARTIFICIAL (decl) = 1;
1951 end_template_decl ();
1952
1953 my_friendly_assert (DECL_TEMPLATE_PARMS (tmpl), 20010110);
1954
1955 return finish_template_type_parm (aggr, tmpl);
1956 }
因为当可选的标识符被读入时,这个模板声明就结束了, end_template_decl 必须被调用来使 processing_template_decl 减一,并跳回该声明的绑定域(看到这是 sk_template_parms )。进一步, finish_template_type_parm 把这个 TEMPLATE_DECL 打包入模板参数的节点。因此在解析缺省参数前,我们得到如下图形。
( 点此打开 )
图 99 :构建的模板模板参数