5.12.4.1.2. 非类型参数
该模板的第二及第三个参数都是非类型参数。它们都指定了类型,但在具现或特化时会分配不同的值。类型描述符( type-specifier )“ std::size_t ”是 simple-type-specifier 的形式。而且, simple-type-specifier “ std::size_t ”包含了两个部分:“ std:: ”构成了 nested-name-specifier ,而“ size_t ”是类型名( type-name )。类型“ size_t ”通常在系统头文件 <stddef.h> 中被 typedef 为“ unsigned long ”,这个头文件通常在目录“ /usr/lib/gcc/`target`/`gcc-v`/include ”下。并且这个“ size_t ”通过 using 指示:“ using ::size_t; ”被引入到文件 <cstddef> 定义的名字空间“ std ”中。这使得“ size_t ”在“ std ”中可见。
这个调用栈是: cp_parser_template_parameter_list à cp_parser_template_parameter à cp_parser_parameter_declaration à cp_parser_decl_specifier_seq à cp_parser_type_specifier à cp_parser_simple_type_specifier à cp_parser_type_name 。
而“ chunkSize ”及“ maxSmallObjectSize ”都是声明符 id ( declarator-id )部分。调用栈: cp_parser_parameter_declaration à cp_parser_declarator à cp_parser_direct_declarator à cp_parser_declarator_id à cp_parser_id_expression à cp_parser_unqualified_id à cp_parser_identifier 为这些声明符构建了 IDENTIFIER_NODE 节点。然后在处理缺省实参之前,向 cp_parser_parameter_declaration 返回以下节点。
( 点此打开 )
图 105 :构建的 decl_specifiers 及 declarator
cp_parser_parameter_declaration (continue)
11311 /* If the next token is `=', then process a default argument. */
11312 if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
11313 {
11314 bool saved_greater_than_is_operator_p;
11315 /* Consume the `='. */
11316 cp_lexer_consume_token (parser->lexer);
11317
11318 /* If we are defining a class, then the tokens that make up the
11319 default argument must be saved and processed later. */
11320 if (!template_parm_p && at_class_scope_p ()
11321 && TYPE_BEING_DEFINED (current_class_type ))
11322 {
…
11406 }
11407 /* Outside of a class definition, we can just parse the
11408 assignment-expression. */
11409 else
11410 {
11411 bool saved_local_variables_forbidden_p;
11412
11413 /* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
11414 set correctly. */
11415 saved_greater_than_is_operator_p
11416 = parser->greater_than_is_operator_p;
11417 parser->greater_than_is_operator_p = greater_than_is_operator_p;
11418 /* Local variable names (and the `this' keyword) may not
11419 appear in a default argument. */
11420 saved_local_variables_forbidden_p
11421 = parser->local_variables_forbidden_p;
11422 parser->local_variables_forbidden_p = true;
11423 /* Parse the assignment-expression. */
11424 default_argument = cp_parser_assignment_expression (parser);
11425 /* Restore saved state. */
11426 parser->greater_than_is_operator_p
11427 = saved_greater_than_is_operator_p;
11428 parser->local_variables_forbidden_p
11429 = saved_local_variables_forbidden_p;
11430 }
11431 if (!parser->default_arg_ok_p)
11432 {
11433 if (!flag_pedantic_errors )
11434 warning ("deprecated use of default argument for parameter of non-function");
11435 else
11436 {
11437 error ("default arguments are only permitted for function parameters");
11438 default_argument = NULL_TREE;
11439 }
11440 }
11441 }
11442 else
11443 default_argument = NULL_TREE;
11444
11445 /* Create the representation of the parameter. */
11446 if (attributes)
11447 decl_specifiers = tree_cons (attributes, NULL_TREE, decl_specifiers);
11448 parameter = build_tree_list (default_argument,
11449 build_tree_list (decl_specifiers,
11450 declarator));
11451
11452 return parameter;
11453 }
在上面注意符号“ = ”在 11316 行被消化,因此在 11424 行后跟的符号被 cp_parser_assignment_expression 所解析。符号“ 4096 ”(通过展开 DEFAULT_CHUNK_SIZE )是 conditional-expression 的一种—— conditional-expression 可以是 logical-or-expression 或者“ logical-or-expression? expression: assignment-expression “。
5161 static tree
5162 cp_parser_assignment_expression (cp_parser* parser) in parser.c
5163 {
5164 tree expr;
5165
5166 /* If the next token is the `throw' keyword, then we're looking at
5167 a throw-expression. */
5168 if (cp_lexer_next_token_is_keyword (parser->lexer, RID_THROW))
5169 expr = cp_parser_throw_expression (parser);
5170 /* Otherwise, it must be that we are looking at a
5171 logical-or-expression. */
5172 else
5173 {
5174 /* Parse the logical-or-expression. */
5175 expr = cp_parser_logical_or_expression (parser);
5176 /* If the next token is a `?' then we're actually looking at a
5177 conditional-expression. */
5178 if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
5179 return cp_parser_question_colon_clause (parser, expr);
5180 else
5181 {
5182 enum tree_code assignment_operator;
5183
5184 /* If it's an assignment-operator, we're using the second
5185 production. */
5186 assignment_operator
5187 = cp_parser_assignment_operator_opt (parser);
5188 if (assignment_operator != ERROR_MARK)
5189 {
5190 tree rhs;
5191
5192 /* Parse the right-hand side of the assignment. */
5193 rhs = cp_parser_assignment_expression (parser);
5194 /* An assignment may not appear in a
5195 constant-expression. */
5196 if (cp_parser_non_integral_constant_expression (parser,
5197 "an assignment"))
5198 return error_mark_node;
5199 /* Build the assignment expression. */
5200 expr = build_x_modify_expr (expr,
5201 assignment_operator,
5202 rhs);
5203 }
5204 }
5205 }
5206
5207 return expr;
5208 }
C++ 语言提供了丰富的算术及逻辑操作符,而且优先级及结合规则顺应常识。在有关编译原理的书籍中,我们可以看到定义体现这些优先级规则的技巧。毫无例外, C++ 的规则采用了相似的技术。例如, logical-or-expression 的规则是:
logical-or-expression:
logical-and-expression
logical-or-expression || logical-and-expression
而且绝大多数的操作符是左结合的二元操作符,例如在 logical-or-expression 中的操作符“ || ”。根据这些形式,以正确的优先级及结合规则处理这些操作符的通用方法是深度优先的遍历。
14059 static tree
14060 cp_parser_binary_expression (cp_parser* parser, in parser.c
14061 const cp_parser_token_tree_map token_tree_map,
14062 cp_parser_expression_fn fn)
14063 {
14064 tree lhs;
14065
14066 /* Parse the first expression. */
14067 lhs = (*fn) (parser);
14068 /* Now, look for more expressions. */
14069 while (true)
14070 {
14071 cp_token *token;
14072 const cp_parser_token_tree_map_node *map_node;
14073 tree rhs;
14074
14075 /* Peek at the next token. */
14076 token = cp_lexer_peek_token (parser->lexer);
14077 /* If the token is `>', and that's not an operator at the
14078 moment, then we're done. */
14079 if (token->type == CPP_GREATER
14080 && !parser->greater_than_is_operator_p)
14081 break ;
14082 /* If we find one of the tokens we want, build the corresponding
14083 tree representation. */
14084 for (map_node = token_tree_map;
14085 map_node->token_type != CPP_EOF;
14086 ++map_node)
14087 if (map_node->token_type == token->type)
14088 {
14089 /* Assume that an overloaded operator will not be used. */
14090 bool overloaded_p = false;
14091
14092 /* Consume the operator token. */
14093 cp_lexer_consume_token (parser->lexer);
14094 /* Parse the right-hand side of the expression. */
14095 rhs = (*fn) (parser);
14096 /* Build the binary tree node. */
14097 lhs = build_x_binary_op (map_node->tree_type, lhs, rhs,
14098 &overloaded_p);
14099 /* If the binary operator required the use of an
14100 overloaded operator, then this expression cannot be an
14101 integral constant-expression. An overloaded operator
14102 can be used even if both operands are otherwise
14103 permissible in an integral constant-expression if at
14104 least one of the operands is of enumeration type. */
14105 if (overloaded_p
14106 && (cp_parser_non_integral_constant_expression
14107 (parser, "calls to overloaded operators")))
14108 lhs = error_mark_node;
14109 break ;
14110 }
14111
14112 /* If the token wasn't one of the ones we want, we're done. */
14113 if (map_node->token_type == CPP_EOF)
14114 break ;
14115 }
14116
14117 return lhs;
14118 }
参数 token_tree_map 具有类型 cp_parser_token_tree_map ,它保存了从一个符号类型到对应树节点类型的映射。
1079 typedef struct cp_parser_token_tree_map_node in parser.c
1080 {
1081 /* The token type. */
1082 ENUM_BITFIELD (cpp_ttype) token_type : 8;
1083 /* The corresponding tree code. */
1084 ENUM_BITFIELD (tree_code) tree_type : 8;
1085 } cp_parser_token_tree_map_node;
1086
1087 /* A complete map consists of several ordinary entries, followed by a
1088 terminator. The terminating entry has a token_type of CPP_EOF. */
1089
1090 typedef cp_parser_token_tree_map_node cp_parser_token_tree_map [];
注意在 14067 及 14095 行对 fn 的调用,变量 lhs 及 rhs 分别是“左手侧“( left hand side )及”右手侧“( right hand side )的缩写。它们是由更高优先级的句柄依次所构建的子树。
对于下面的每个函数,数组 map 记录了该函数所处理的操作符,对于该操作符, cp_parser_binary_expression 将被用于把 lhs 及 rhs 部分组织成相应的表达式。注意到 CPP_EOF 必须在作为数组的最后一个成员来确保,当 rhs 缺失时,正确退出 14084 行的 FOR 循环。
而且看到这是对表达式的一个前序遍历。因此对于我们的例子,符号“ 4096 “经历一个深的,具有以下函数的调用栈 。
对于操作符“ && ”,它优先于“ || ”,因此应用的规则是:
logical-or-expression:
logical-and-expression
logical-or-expression || logical-and-expression
5099 static tree
5100 cp_parser_logical_or_expression (cp_parser* parser) in parser.c
5101 {
5102 static const cp_parser_token_tree_map map = {
5103 { CPP_OR_OR, TRUTH_ORIF_EXPR },
5104 { CPP_EOF, ERROR_MARK }
5105 };
5106
5107 return cp_parser_binary_expression (parser,
5108 map,
5109 cp_parser_logical_and_expression );
5110 }
依次的,“ | ”在下面的规则中,优先级又高一些:
logical-and-expression:
inclusive-or-expression
logical-and-expression && inclusive-or-expression
5078 static tree
5079 cp_parser_logical_and_expression (cp_parser* parser) in parser.c
5080 {
5081 static const cp_parser_token_tree_map map = {
5082 { CPP_AND_AND, TRUTH_ANDIF_EXPR },
5083 { CPP_EOF, ERROR_MARK }
5084 };
5085
5086 return cp_parser_binary_expression (parser,
5087 map,
5088 cp_parser_inclusive_or_expression );
5089 }
接下来优先级又高一点的是“ ^ ”:
inclusive-or-expression:
exclusive-or-expression
inclusive-or-expression | exclusive-or-expression
5057 static tree
5058 cp_parser_inclusive_or_expression (cp_parser* parser) in parser.c
5059 {
5060 static const cp_parser_token_tree_map map = {
5061 { CPP_OR, BIT_IOR_EXPR },
5062 { CPP_EOF, ERROR_MARK }
5063 };
5064
5065 return cp_parser_binary_expression (parser,
5066 map,
5067 cp_parser_exclusive_or_expression );
5068 }
而规则 exclusive-or-expression 如下所示:
exclusive-or-expression:
and-expression
exclusive-or-expression ^ and-expression
5035 static tree
5036 cp_parser_exclusive_or_expression (cp_parser* parser) in parser.c
5037 {
5038 static const cp_parser_token_tree_map map = {
5039 { CPP_XOR, BIT_XOR_EXPR },
5040 { CPP_EOF, ERROR_MARK }
5041 };
5042
5043 return cp_parser_binary_expression (parser,
5044 map,
5045 cp_parser_and_expression );
5046 }
而 and-expression 是具有以下规则的表达式:
and-expression:
equality-expression
and-expression & equality-expression
5014 static tree
5015 cp_parser_and_expression (cp_parser* parser) in parser.c
5016 {
5017 static const cp_parser_token_tree_map map = {
5018 { CPP_AND, BIT_AND_EXPR },
5019 { CPP_EOF, ERROR_MARK }
5020 };
5021
5022 return cp_parser_binary_expression (parser,
5023 map,
5024 cp_parser_equality_expression );
5025 }
操作符“ == ”及“ != ”,在关系操作符中,具有最低的优先级。
equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression
4992 static tree
4993 cp_parser_equality_expression (cp_parser* parser) in parser.c
4994 {
4995 static const cp_parser_token_tree_map map = {
4996 { CPP_EQ_EQ, EQ_EXPR },
4997 { CPP_NOT_EQ, NE_EXPR },
4998 { CPP_EOF, ERROR_MARK }
4999 };
5000
5001 return cp_parser_binary_expression (parser,
5002 map,
5003 cp_parser_relational_expression );
5004 }
GNU 提供扩展的关系操作符 “ <? ”及“ >? ”,其中“ <? ”返回两者中较小的那个,而“ >? ”则返回较大的那个。
relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-ex pression
relational-expression <= shift-expression
relational-expression >= shift-expression
GNU Extension:
relational-expression:
relational-expression <? shift-expression
relational-expression >? shift-expression
4965 static tree
4966 cp_parser_relational_expression (cp_parser* parser) in parser.c
4967 {
4968 static const cp_parser_token_tree_map map = {
4969 { CPP_LESS, LT_EXPR },
4970 { CPP_GREATER, GT_EXPR },
4971 { CPP_LESS_EQ, LE_EXPR },
4972 { CPP_GREATER_EQ, GE_EXPR },
4973 { CPP_MIN, MIN_EXPR },
4974 { CPP_MAX, MAX_EXPR },
4975 { CPP_EOF, ERROR_MARK }
4976 };
4977
4978 return cp_parser_binary_expression (parser,
4979 map,
4980 cp_parser_shift_expression );
4981 }
然后, shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression
4934 static tree
4935 cp_parser_shift_expression (cp_parser* parser) in parser.c
4936 {
4937 static const cp_parser_token_tree_map map = {
4938 { CPP_LSHIFT, LSHIFT_EXPR },
4939 { CPP_RSHIFT, RSHIFT_EXPR },
4940 { CPP_EOF, ERROR_MARK }
4941 };
4942
4943 return cp_parser_binary_expression (parser,
4944 map,
4945 cp_parser_additive_expression );
4946 }
additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression
4911 static tree
4912 cp_parser_additive_expression (cp_parser* parser) in parser.c
4913 {
4914 static const cp_parser_token_tree_map map = {
4915 { CPP_PLUS, PLUS_EXPR },
4916 { CPP_MINUS, MINUS_EXPR },
4917 { CPP_EOF, ERROR_MARK }
4918 };
4919
4920 return cp_parser_binary_expression (parser,
4921 map,
4922 cp_parser_multiplicative_expression );
4923 }
mulitplicative-expression:
pm-expression
multiplicative-expression * pm-expression
multiplicative-expression / pm-expression
multiplicative-expression % pm-expression
4887 static tree
4888 cp_parser_multiplicative_expression (cp_parser* parser) in parser.c
4889 {
4890 static const cp_parser_token_tree_map map = {
4891 { CPP_MULT, MULT_EXPR },
4892 { CPP_DIV, TRUNC_DIV_EXPR },
4893 { CPP_MOD, TRUNC_MOD_EXPR },
4894 { CPP_EOF, ERROR_MARK }
4895 };
4896
4897 return cp_parser_binary_expression (parser,
4898 map,
4899 cp_parser_pm_expression );
4900 }
Pm-expression 是指向成员指针( pointer-to-member )表达式的缩写,它可能包含指向成员操作符“ .* ”或“ ->* ”。
pm-expression:
cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression
4864 static tree
4865 cp_parser_pm_expression (cp_parser* parser) in parser.c
4866 {
4867 static const cp_parser_token_tree_map map = {
4868 { CPP_DEREF_STAR, MEMBER_REF },
4869 { CPP_DOT_STAR, DOTSTAR_EXPR },
4870 { CPP_EOF, ERROR_MARK }
4871 };
4872
4873 return cp_parser_binary_expression (parser, map,
4874 cp_parser_simple_cast_expression );
4875 }
在指向成员指针操作符两边可以是转换表达式( cast-expression )。
cast-expression:
unary-expression
( type-id ) cast-expression
14595 static tree
14596 cp_parser_simple_cast_expression (cp_parser *parser) in parser.c
14597 {
14598 return cp_parser_cast_expression (parser, /*address_p=*/ false);
14599 }
Cast-expression 包含属于非转换表达式的一元表达式( unary-expression ),它是符号“ 4096 ” 所从属的表达式类别。
4751 static tree
4752 cp_parser_cast_expression (cp_parser *parser, bool address_p) in parser.c
4753 {
4754 /* If it's a `(', then we might be looking at a cast. */
4755 if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
4756 {
…
4848 }
4849
4850 /* If we get here, then it's not a cast, so it must be a
4851 unary-expression. */
4852 return cp_parser_unary_expression (parser, address_p);
4853 }
Unary-epxression 包含丰富的规则,而且 GNU 还支持几个扩展。
unary-expression:
postfix-expression
++ cast-expression
-- cast-expression
unary-operator cast-expression
sizeof unary-expression
sizeof ( type-id )
new-expression
delete-expression
GNU Extensions:
unary-expression:
__extension__ cast-expression
__alignof__ unary-expression
__alignof__ ( type-id )
__real__ cast-expression
__imag__ cast-expression
&& identifier
4235 static tree
4236 cp_parser_unary_expression (cp_parser *parser, bool address_p) in parser.c
4237 {
4238 cp_token *token;
4239 enum tree_code unary_operator;
4240
4241 /* Peek at the next token. */
4242 token = cp_lexer_peek_token (parser->lexer);
…
4406 return cp_parser_postfix_expression (parser, address_p);
4407 }
postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression ( expression-list [opt] )
simple-type-specifier ( expression-list [opt] )
typename :: [opt] nested-name-specifier identifier ( expression-list [opt] )
typename :: [opt] nested-name-specifier template [opt] template-id (expression-list [opt])
postfix-expression . template [opt] id-expression
postfix-expression -> template [opt] id-expression
postfix-expression . pseudo-destructor-name
postfix-expression -> pseudo-destructor-name
postfix-expression ++
postfix-expression --
dynamic_cast < type-id > ( expression )
static_cast < type-id > ( expression )
reinterpret_cast < type-id > ( expression )
const_cast < type-id > ( expression )
typeid ( expression )
typeid ( type-id )
GNU Extension:
postfix-expression:
( type-id ) { initializer-list , [opt] }
Postfix-expression 可以被用作:下标,函数调用,显式类型转换(函数记号),伪析构函数调用( pseudo destructor call ),类成员访问,自增及自减,动态类型转换( dynamic cast ),类型识别( type identification ),静态类型转换( static cast ),重解释转换( reinterpret cast ),常量类型转换( constant cast )。
3414 static tree
3415 cp_parser_postfix_expression (cp_parser *parser, bool address_p) in parser.c
3416 {
3417 cp_token *token;
3418 enum rid keyword;
3419 cp_id_kind idk = CP_ID_KIND_NONE;
3420 tree postfix_expression = NULL_TREE;
3421 /* Non-NULL only if the current postfix-expression can be used to
3422 form a pointer-to-member. In that case, QUALIFYING_CLASS is the
3423 class used to qualify the member. */
3424 tree qualifying_class = NULL_TREE;
3425
3426 /* Peek at the next token. */
3427 token = cp_lexer_peek_token (parser->lexer);
3428 /* Some of the productions are determined by keywords. */
3429 keyword = token->keyword;
3430 switch (keyword)
3431 {
….
3566 default :
3567 {
3568 tree type;
3569
3570 /* If the next thing is a simple-type-specifier, we may be
3571 looking at a functional cast. We could also be looking at
3572 an id-expression. So, we try the functional cast, and if
3573 that doesn't work we fall back to the primary-expression. */
3574 cp_parser_parse_tentatively (parser);
3575 /* Look for the simple-type-specifier. */
3576 type = cp_parser_simple_type_specifier (parser,
3577 CP_PARSER_FLAGS_NONE,
3578 /*identifier_p=*/ false);
3579 /* Parse the cast itself. */
3580 if (!cp_parser_error_occurred (parser))
3581 postfix_expression
3582 = cp_parser_functional_cast (parser, type);
3583 /* If that worked, we're done. */
3584 if (cp_parser_parse_definitely (parser))
3585 break ;
3586
3587 /* If the functional-cast didn't work out, try a
3588 compound-literal. */
3589 if (cp_parser_allow_gnu_extensions_p (parser)
3590 && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
3591 {
…
3634 }
3635
3636 /* It must be a primary-expression. */
3637 postfix_expression = cp_parser_primary_expression (parser,
3638 &idk,
3639 &qualifying_class);
3640 }
3641 break ;
3642 }
3643
3644 /* If we were avoiding committing to the processing of a
3645 qualified-id until we knew whether or not we had a
3646 pointer-to-member, we now know. */
3647 if (qualifying_class)
3648 {
…
3666 }
3667
3668 /* Keep looping until the postfix-expression is complete. */
3669 while (true)
3670 {
3671 if (idk == CP_ID_KIND_UNQUALIFIED
3672 && TREE_CODE (postfix_expression) == IDENTIFIER_NODE
3673 && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
3674 /* It is not a Koenig lookup function call. */
3675 postfix_expression
3676 = unqualified_name_lookup_error (postfix_expression);
3677
3678 /* Peek at the next token. */
3679 token = cp_lexer_peek_token (parser->lexer);
3680
3681 switch (token->type)
3682 {
…
4003 default :
4004 return postfix_expression;
4005 }
4006 }
4007
4008 /* We should never get here. */
4009 abort ();
4010 return error_mark_node;
4011 }
上面,对于符号“ 4096 ”,它不是上面提及的形式,此外它也不是简单类型指示符( simple-type-specifier ),亦不是函数转换,那么解析器需要按以下规则将其作为 primary-expression 来处理。
primary-expression:
literal
this
( expression )
id-expression
GNU Extensions:
primary-expression:
( compound-statement )
__builtin_va_arg ( assignment-expression , type-id )
literal:
__null
2373 static tree
2374 cp_parser_primary_expression (cp_parser *parser, in parser.c
2375 cp_id_kind *idk,
2376 tree *qualifying_class)
2377 {
2378 cp_token *token;
2379
2380 /* Assume the primary expression is not an id-expression. */
2381 *idk = CP_ID_KIND_NONE;
2382 /* And that it cannot be used as pointer-to-member. */
2383 *qualifying_class = NULL_TREE;
2384
2385 /* Peek at the next token. */
2386 token = cp_lexer_peek_token (parser->lexer);
2387 switch (token->type)
2388 {
2389 /* literal:
2390 integer-literal
2391 character-literal
2392 floating-literal
2393 string-literal
2394 boolean-literal */
2395 case CPP_CHAR:
2396 case CPP_WCHAR:
2397 case CPP_STRING:
2398 case CPP_WSTRING:
2399 case CPP_NUMBER:
2400 token = cp_lexer_consume_token (parser->lexer);
2401 return token->value;
…
2648 }
2649 }
显然,符号“ 4096 ”是 literal 规则中的整形文本( integer-literal )。事实上,当词法分析器读入这个符号时,一个整形常量树节点被构建出来,并且被设置为该符号的值。其细节参考章节 5.6.1.1.2. 数字 。在为缺省实参构建了节点之后,为模板参数所建立的子树显示如下。
( 点此打开 )
图 106 :非类型参数