跟在 template-parameter-list 后的符号是“ class ”,这标记着这是类模板的定义 / 声明。与前面的例子相同,沿着下面的调用栈: cp_parser_template_declaration_after_export à cp_parser_single_declaration à cp_parser_decl_specifier_seq à cp_parser_type_specifier , 关键字“ class ”把解析器导向函数 cp_parser_class_specifier 。
11855 static tree
11856 cp_parser_class_specifier (cp_parser* parser) in parser.c
11857 {
11858 cp_token *token;
11859 tree type;
11860 tree attributes;
11861 int has_trailing_semicolon;
11862 bool nested_name_specifier_p;
11863 unsigned saved_num_template_parameter_lists;
11864 bool pop_p = false;
11865 tree scope = NULL_TREE;
11866
11867 push_deferring_access_checks (dk_no_deferred);
11868
11869 /* Parse the class-head. */
11870 type = cp_parser_class_head (parser,
11871 &nested_name_specifier_p,
11872 &attributes);
在解析 class-specifier 时,访问性检查通常应该执行而不作任何延迟,这反映在 11867 行所插入的 dk_no_deferred 节点。不过,后面我们可以看到在布局可能有不同的访问性检查。
12030 static tree
12031 cp_parser_class_head (cp_parser* parser, in parser.c
12032 bool* nested_name_specifier_p,
12033 tree *attributes_p)
12034 {
12035 cp_token *token;
12036 tree nested_name_specifier;
12037 enum tag_types class_key;
12038 tree id = NULL_TREE;
12039 tree type = NULL_TREE;
12040 tree attributes;
12041 bool template_id_p = false;
12042 bool qualified_p = false;
12043 bool invalid_nested_name_p = false;
12044 bool invalid_explicit_specialization_p = false;
12045 bool pop_p = false;
12046 unsigned num_templates;
12047
12048 /* Assume no nested-name-specifier will be present. */
12049 *nested_name_specifier_p = false;
12050 /* Assume no template parameter lists will be used in defining the
12051 type. */
12052 num_templates = 0;
12053
12054 /* Look for the class-key. */
12055 class_key = cp_parser_class_key (parser);
12056 if (class_key == none_type)
12057 return error_mark_node;
12058
12059 /* Parse the attributes. */
12060 attributes = cp_parser_attributes_opt (parser);
12061
12062 /* If the next token is `::', that is invalid -- but sometimes
12063 people do try to write:
12064
12065 struct ::S {};
12066
12067 Handle this gracefully by accepting the extra qualifier, and then
12068 issuing an error about it later if this really is a
12069 class-head. If it turns out just to be an elaborated type
12070 specifier, remain silent. */
12071 if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/ false))
12072 qualified_p = true;
12073
12074 push_deferring_access_checks (dk_no_check);
12075
12076 /* Determine the name of the class. Begin by looking for an
12077 optional nested-name-specifier. */
12078 nested_name_specifier
12079 = cp_parser_nested_name_specifier_opt (parser,
12080 /*typename_keyword_p=*/ false,
12081 /*check_dependency_p=*/ false,
12082 /*type_p=*/ false,
12083 /*is_declaration=*/ false);
12084 /* If there was a nested-name-specifier, then there *must* be an
12085 identifier. */
12086 if (nested_name_specifier)
12087 {
…
12143 }
12144 /* Otherwise, the identifier is optional. */
12145 else
12146 {
12147 /* We don't know whether what comes next is a template-id,
12148 an identifier, or nothing at all. */
12149 cp_parser_parse_tentatively (parser);
12150 /* Check for a template-id. */
12151 id = cp_parser_template_id (parser,
12152 /*template_keyword_p=*/ false,
12153 /*check_dependency_p=*/ true,
12154 /*is_declaration=*/ true);
12155 /* If that didn't work, it could still be an identifier. */
12156 if (!cp_parser_parse_definitely (parser))
12157 {
12158 if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
12159 id = cp_parser_identifier (parser);
12160 else
12161 id = NULL_TREE;
12162 }
12163 else
12164 {
12165 template_id_p = true;
12166 ++num_templates;
12167 }
12168 }
12169
12170 pop_deferring_access_checks ();
这里看到,在 12074 行加入了对访问性不作检查规则。这一规则将影响在 12149 行由 cp_parser_parse_tentatively 加入的访问性检查规则,使其也成为 dk_no_check 。在本例中,关键字“ class ”后的符号是“ SmallObject ”,这是一个标识符,由 12159 行的 cp_parser_identifier 识别。
注意 pop_deferring_access_checks 相应地弹出 dk_no_checks 节点。
cp_parser_class_head (continue)
12259 /* Look up the type. */
12260 if (template_id_p)
12261 {
12262 type = TREE_TYPE (id);
12263 maybe_process_partial_specialization (type);
12264 }
12265 else if (!nested_name_specifier)
12266 {
12267 /* If the class was unnamed, create a dummy name. */
12268 if (!id)
12269 id = make_anon_name ();
12270 type = xref_tag (class_key, id, /*globalize=*/ false,
12271 parser->num_template_parameter_lists);
12272 }
符号“ class SmallObject ”作为类标签( class tag )的处理与章节 加入类 SingleThreaded的标签 所描述的一样。因此我们跳过这部分的细节避免重复。
基类必须是已经定义的类型,从类名找到对应的类型节点,是一个复杂的过程,尤其是当这个类是一个模板类。下面首先看一下类名的查找过程。不过,在此之前,我们最好看看如何来确定给定名字的依赖性。
在一个模板里,某些构造的语义可能在不同的具现中有所不同。这样的构造依赖于模板参数。特别的,类型及表达式可能依赖于模板参数的类型及值(即由模板实参确定),并且其也确定了查找这些名字的作用域。表达式可能是依赖类型的(模板参数的类型)或者是依赖于值的(模板非类型参数的值)。在一个具有以下形式的表达式中:
postfix-expression ( expression-list opt )
其中 postfix-expression 部分是一个标识符,该标识符表示一个依赖名,当且仅当 expression-list 部分中任一表达式是类型依赖的( 14.6.2 .2 )。如果一个操作符的一个操作数是一个类型依赖表达式,该操作数同样表示一个依赖名。这样的名字是未绑定的,并且在模板具现( 14.6.4.1 )这一点上,在模板定义的上下文及具现点的上下文中查找。 [ 例如:
template <class T> struct X : B<T> {
typename T::A* pa;
void f(B<T>* pb) {
static int i = B<T>::i;
pb->j++;
}
};
基类名 B<T> ,类型名 T::A ,名字 B<T>::i 及 pb->j 显然依赖于模板参数。
在一个类模板或类模板的一个成员定义中,如果该类模板的一个基类依赖于一个模板参数,该基类的作用域,在类模板或其成员的定义这一点上的非限定名查找中,或者在该类模板或其成员的一个具现过程中,不作考察。 [ 例如:
typedef double A;
template <class T> class B {
typedef int A;
};
template <class T> struct X : B<T> {
A a; // a has type double
};
在 X<T> 定义中的类型名 A 绑定到在全局名字空间中定义的 typedef 名,而不是绑定到在基类 B<T> 中定义的 typedef 名。 [ 例如:
struct A {
struct B { /* ... */ };
int a;
int Y;
};
int a;
template <class T> struct Y : T {
struct B { /* ... */ };
B b; // The B defined in Y
void f(int i) { a = i; } // ::a
Y* p; // Y<T>
};
Y<A> ya;
模板实参 A 的成员 A::B , A::a 及 A::Y 不影响在 Y<A> 中的名字绑定。
函数 type_dependent_expression_p 返回 true 如果参数 expression 是依赖类型的。
11966 bool
11967 type_dependent_expression_p (tree expression) in pt.c
11968 {
11969 if (!processing_template_decl )
11970 return false;
11971
11972 if (expression == error_mark_node)
11973 return false;
11974
11975 /* An unresolved name is always dependent. */
11976 if (TREE_CODE (expression) == IDENTIFIER_NODE)
11977 return true;
我们已经知道当解析器找到一个标识符时,它总是尝试查找这个名字以找出当前绑定的声明。该声明就是当前要用的那个对象,这通常是一个 *_DECL 节点。但是如果该标识符在当前作用域没有可见的绑定,解析器只能使用 IDENTIFIER_NODE 。例如上面例子中的:
template <class T> struct X : B<T> {
typename T::A* pa;
在 “ T::A ” 中的 “ A ”, 在此处只能是 IDENTIFIER_NODE 。
type_dependent_expression_p (continue)
11979 /* Some expression forms are never type-dependent. */
11980 if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR
11981 || TREE_CODE (expression) == SIZEOF_EXPR
11982 || TREE_CODE (expression) == ALIGNOF_EXPR
11983 || TREE_CODE (expression) == TYPEID_EXPR
11984 || TREE_CODE (expression) == DELETE_EXPR
11985 || TREE_CODE (expression) == VEC_DELETE_EXPR
11986 || TREE_CODE (expression) == THROW_EXPR)
11987 return false;
11988
11989 /* The types of these expressions depends only on the type to which
11990 the cast occurs. */
11991 if (TREE_CODE (expression) == DYNAMIC_CAST_EXPR
11992 || TREE_CODE (expression) == STATIC_CAST_EXPR
11993 || TREE_CODE (expression) == CONST_CAST_EXPR
11994 || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
11995 || TREE_CODE (expression) == CAST_EXPR)
11996 return dependent_type_p (TREE_TYPE (expression));
11997
11998 /* The types of these expressions depends only on the type created
11999 by the expression. */
12000 if (TREE_CODE (expression) == NEW_EXPR
12001 || TREE_CODE (expression) == VEC_NEW_EXPR)
12002 {
12003 /* For NEW_EXPR tree nodes created inside a template, either
12004 the object type itself or a TREE_LIST may appear as the
12005 operand 1. */
12006 tree type = TREE_OPERAND (expression, 1);
12007 if (TREE_CODE (type) == TREE_LIST)
12008 /* This is an array type. We need to check array dimensions
12009 as well. */
12010 return dependent_type_p (TREE_VALUE (TREE_PURPOSE (type)))
12011 || value_dependent_expression_p
12012 (TREE_OPERAND (TREE_VALUE (type), 1));
12013 else
12014 return dependent_type_p (type);
12015 }
12016
12017 if (TREE_CODE (expression) == SCOPE_REF
12018 && dependent_scope_ref_p (expression,
12019 type_dependent_expression_p))
12020 return true;
12021
12022 if (TREE_CODE (expression) == FUNCTION_DECL
12023 && DECL_LANG_SPECIFIC (expression)
12024 && DECL_TEMPLATE_INFO (expression)
12025 && (any_dependent_template_arguments_p
12026 (INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
12027 return true;
12028
12029 if (TREE_CODE (expression) == TEMPLATE_DECL
12030 && !DECL_TEMPLATE_TEMPLATE_PARM_P (expression))
12031 return false;
根据【 3 】,下列形式是不可能类型依赖的。
literal
postfix-expression.pseduo-destructor-name
postfix-expression->pseduo-destructor-name
sizeof unary-expression
sizeof (type-id)
typeid (expression)
typeid (type-id)
::opt delete cast-expression
::opt delete[] cast-expression
throw assignment-expression opt
因为这些表达式的类型不会是依赖的。例如, sizeof 的类型总是 size_t 。 GNU 的扩展操作符 alignof 也在这个类别中(它的类型也是 size_t )。
那么一个 id-expression 是类型依赖的,如果它包含:
一个以依赖类型声明的标识符 identifier
一个依赖的 template-id
一个指定一个依赖类型的 conversion-function-id
一个包含命名了一个依赖名的类名的 nested-name-specifier
以下形式的表达式,即使任一子表达式是类型依赖的,仅当由 type-id , simple-type-specifier 或 new-type-id 指定的类型是依赖的,才是是类型依赖的:
simple-type-specifier (expression-list opt )
::opt new new-placement opt new-type-id new-initializer opt
::opt new new-placement opt (type-id ) new-initializer opt
dynamic_cast <type-id > (expression)
static_cast <type-id > (expression)
const_cast <type-id > (expression)
reinterpret_cast <type-id > (expression)
(type-id ) cast-expression
上面规则的核心是检查表达式所包含的类型的类型依赖性。上面的 12000 行,注意对于 new-type-id ,其语法为:
new-type-id
type-specifier-seq new-declarator opt
new-declarator:
ptr-operator new-declarator opt
direct-new-declarator
direct-new-declarator:
[expression]
direct-new-declarator [constant-expression]
对于这个情形, NEW_EXPR/VEC_NEW_EXPR 节点中索引为 1 (从 0 开始)的操作数是 new-type-id ,它是应该 tree_list ,其 purpose 域保存了 type-specifier-seq 部分, value 域是 new-declarator 部分。如果 new-declarator 导出 direct-new-declarator ,它是 ARRAY_REF 节点,用作子维的 direct-new-declarator 是操作数 0 ,表示维度大小的表达式是操作数 1 。显然如果这个表达式是值依赖的, new-type-id 就视为类型依赖。
那么 dependent_type_p 验证传入的 type 是否依赖模板参数。
11786 bool
11787 dependent_type_p (tree type) in pt.c
11788 {
11789 /* If there are no template parameters in scope, then there can't be
11790 any dependent types. */
11791 if (!processing_template_decl )
11792 return false;
11793
11794 /* If the type is NULL, we have not computed a type for the entity
11795 in question; in that case, the type is dependent. */
11796 if (!type)
11797 return true;
11798
11799 /* Erroneous types can be considered non-dependent. */
11800 if (type == error_mark_node)
11801 return false;
11802
11803 /* If we have not already computed the appropriate value for TYPE,
11804 do so now. */
11805 if (!TYPE_DEPENDENT_P_VALID (type))
11806 {
11807 TYPE_DEPENDENT_P (type) = dependent_type_p_r (type);
11808 TYPE_DEPENDENT_P_VALID (type) = 1;
11809 }
11810
11811 return TYPE_DEPENDENT_P (type);
11812 }
为了加速编译速度,某些类型如果已经经过评估,其树节点的 lang_flag_6 域已被设置( TYPE_DEPENDENT_P_VALID ),且 lang_flag_0 域保存了结果( TYPE_DEPENDENT_P )。
一个类型是依赖的如果它是:
1) 一个模板参数
2) 一个 qualified-id 。它具有一个 nested-name-specifier ,其包含了一个命名了一个依赖类型的类名;或其 unqualified-id 命名了一个依赖类型。
3) 一个 cv-qualified 类型,其 cv-unqualified 类型是依赖的。
4) 一个从任一依赖类型构建的复合类型。
5) 从任一依赖类型构建的数组,或者由常量表达式所表示的数组的大小是值依赖的。
6) 一个 template-id 。其模板名是一个模板参数; 或者其任一实参是依赖类型或类型依赖或值依赖的表达式。
下面, TEMPLATE_TYPE_PARM 是代表模板参数的节点,作为参数的模板的本身是 TEMPLATE_TEMPLATE_PARM 节点。
那么根据【 3 】 ISO-IE-14882-2003 , 14.6 名字解析( name resolution ):
一个在一个模板声明或模板定义中使用的依赖于模板参数的名字,其命名的假定不为类型,除非适用的名字查找找出一个类型名或者该名字为关键字 typename 所限定。
例如:
// no B declared here
class X;
template <class T> class Y {
class Z; // forward declaration of member class
void f() {
X* a1; // declare pointer to X
T* a2; // declare pointer to T
Y* a3; // declare pointer to Y
Z* a4; // declare pointer to Z
typedef typename T::A TA;
TA* a5; // declare pointer to T’s A
typename T::A* a6; // declare pointer to T’s A
T::A* a7; // T::A is not a type name: mulitply T::A by a7;
// ill-formed, no visible declaration of a7
B* a8; // multiply B by a8; ill-formed, no visible declaration of B and a8
}
};
一个引用一个类型并且依赖于模板参数的限定名应该使用关键字 typename 作为前缀,来表示该限定名表示一个类型,构成一个 elaborated-type specifier 。
elaborated-type-specifier:
typename ::opt nested-name-specifier identifier
typename ::opt nested-name-specifier identifer <template-argument-list>
关键字 typename 只能用在模板声明及定义中,包括在函数模板或成员函数模板的返回类型中,类模板或其嵌套类的成员函数定义中返回类型里,及在类模板或其嵌套类的静态成员的 type-specifier 中。关键字 typename 只能用于限定名字,但这些名字不需要是依赖的。关键字 typename 在 base-specifier 或 mem-initializer 中是不被允许的;在这些上下文中一个依赖于模板参数的限定名被隐含地认为是一个类型名。
在一个类模板或类模板的成员的定义中,当引用一个先前已声明的成员,且该成员声明了一个类型时,不要求使用关键字 typename 。当使用限定名来引用成员时,即是该限定名就是该类模板名,要指明关键字 typename 。
例如:
template <class T> struct A {
typedef int B;
A::B b; // ill-formed: typename required before A::B
void f(A<T>::B); // ill-formed: typename required before A<T>::B
typename A::B g(); // OK
};
不管使用的限定名是 A 还是 A<T> ,都要求使用关键字 typename ,因为在具有参数列表 <T> 的类模板中, A 及 A<T> 是同义词。
根据上面的描述,如果一个模板被正确声明了,关键字 typename 总是表示一个依赖类型。因此在下面的 11704 行,如果我们看到 typename ,我们就可以安全地假定依赖于类型,反之亦然(如果模板被错误声明,比如缺少了 typename ,后面的解析将发出错误信息)。函数 dependent_type_p_r 执行检查。
11686 static bool
11687 dependent_type_p_r (tree type) in pt.c
11688 {
11689 tree scope;
11690
11691 /* [temp.dep.type]
11692
11693 A type is dependent if it is:
11694
11695 -- a template parameter. Template template parameters are
11696 types for us (since TYPE_P holds true for them) so we
11697 handle them here. */
11698 if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
11699 || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
11700 return true;
11701 /* -- a qualified-id with a nested-name-specifier which contains a
11702 class-name that names a dependent type or whose unqualified-id
11703 names a dependent type. */
11704 if (TREE_CODE (type) == TYPENAME_TYPE)
11705 return true;
11706 /* -- a cv-qualified type where the cv-unqualified type is
11707 dependent. */
11708 type = TYPE_MAIN_VARIANT (type);
11709 /* -- a compound type constructed from any dependent type. */
11710 if (TYPE_PTR_TO_MEMBER_P (type))
11711 return (dependent_type_p (TYPE_PTRMEM_CLASS_TYPE (type))
11712 || dependent_type_p (TYPE_PTRMEM_POINTED_TO_TYPE
11713 (type)));
11714 else if (TREE_CODE (type) == POINTER_TYPE
11715 || TREE_CODE (type) == REFERENCE_TYPE)
11716 return dependent_type_p (TREE_TYPE (type));
11717 else if (TREE_CODE (type) == FUNCTION_TYPE
11718 || TREE_CODE (type) == METHOD_TYPE)
11719 {
11720 tree arg_type;
11721
11722 if (dependent_type_p (TREE_TYPE (type)))
11723 return true;
11724 for (arg_type = TYPE_ARG_TYPES (type);
11725 arg_type;
11726 arg_type = TREE_CHAIN (arg_type))
11727 if (dependent_type_p (TREE_VALUE (arg_type)))
11728 return true;
11729 return false;
11730 }
在 11710 行,如果 type 是指向类数据成员或方法的指针, TYPE_PTR_TO_MEMBER_P 不为 0 ,而对于类型 T X::* , TYPE_PTRMEM_CLASS_TYPE 返回 X , TYPE_PTRMEM_CLASS_TYPE 返回 T 。
对 FUNCTION_DECL(function) 或 METHOD_DECL(method of class) , TREE_TYPE 返回其返回类型,而 TREE_ARG_TYPE 返回实参列表。
dependent_type_p_r (continue)
11731 /* -- an array type constructed from any dependent type or whose
11732 size is specified by a constant expression that is
11733 value-dependent. */
11734 if (TREE_CODE (type) == ARRAY_TYPE)
11735 {
11736 if (TYPE_DOMAIN (type)
11737 && ((value_dependent_expression_p
11738 (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
11739 || (type_dependent_expression_p
11740 (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))))
11741 return true;
11742 return dependent_type_p (TREE_TYPE (type));
11743 }
一个数组的边界的类型由 TYPE_DOMAIN 访问,而其上下边界可分别由 TYPE_MAX_VALUE 及 TYPE_MIN_VALUE 得到。
在上面的类型依赖性条件,由条款 5 ,一个数组是类型依赖的,如果其大小由一个值依赖的常量表达式指定。那么怎么算值依赖呢?
值依赖的表达式应该是:
除以下描述的之外,一个常量表达式是值依赖的,如果任一子表达式是值依赖的。
一个标识符是值依赖的,如果它是:
以依赖类型声明的名字。
模板非类型参数的名字。
一个整型或枚举类型的常量,由一个值依赖的表达式初始化。
以下形式的表达式是值依赖的,如果 unary-expression 部分依赖类型或 type-id 部分是依赖性的(即使 sizeof unary-expression 及 sizeof (type-id) 不是类型依赖的): sizeof unary-expression, sizeof (type-id) 。
以下形式的表达式是值依赖的,如果 type-id 或 simple-type-specifier 部分是依赖的,或者 expression 或 cast-expression 部分是值依赖的:
simple-type-specifier (expression-list opt )
static_cast <type-id> (expression)
const_cast <type-id> (expression)
reinterpret_cast <type-id> (expression)
(type-id) cast-expression
11851 bool
11852 value_dependent_expression_p (tree expression) in pt.c
11853 {
11854 if (!processing_template_decl )
11855 return false;
11856
11857 /* A name declared with a dependent type. */
11858 if (TREE_CODE (expression) == IDENTIFIER_NODE
11859 || (DECL_P (expression)
11860 && type_dependent_expression_p (expression)))
11861 return true;
11862 /* A non-type template parameter. */
11863 if ((TREE_CODE (expression) == CONST_DECL
11864 && DECL_TEMPLATE_PARM_P (expression))
11865 || TREE_CODE (expression) == TEMPLATE_PARM_INDEX)
11866 return true;
11867 /* A constant with integral or enumeration type and is initialized
11868 with an expression that is value-dependent. */
11869 if (TREE_CODE (expression) == VAR_DECL
11870 && DECL_INITIAL (expression)
11871 && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (expression))
11872 && value_dependent_expression_p (DECL_INITIAL (expression)))
11873 return true;
11874 /* These expressions are value-dependent if the type to which the
11875 cast occurs is dependent or the expression being casted is
11876 value-dependent. */
11877 if (TREE_CODE (expression) == DYNAMIC_CAST_EXPR
11878 || TREE_CODE (expression) == STATIC_CAST_EXPR
11879 || TREE_CODE (expression) == CONST_CAST_EXPR
11880 || TREE_CODE (expression) == REINTERPRET_CAST_EXPR
11881 || TREE_CODE (expression) == CAST_EXPR)
11882 {
11883 tree type = TREE_TYPE (expression);
11884 if (dependent_type_p (type))
11885 return true;
11886 /* A functional cast has a list of operands. */
11887 expression = TREE_OPERAND (expression, 0);
11888 if (!expression)
11889 {
11890 /* If there are no operands, it must be an expression such
11891 as "int()". This should not happen for aggregate types
11892 because it would form non-constant expressions. */
11893 my_friendly_assert (INTEGRAL_OR_ENUMERATION_TYPE_P (type),
11894 20040318);
11895
11896 return false;
11897 }
11898 if (TREE_CODE (expression) == TREE_LIST)
11899 {
11900 do
11901 {
11902 if (value_dependent_expression_p (TREE_VALUE (expression)))
11903 return true;
11904 expression = TREE_CHAIN (expression);
11905 }
11906 while (expression);
11907 return false;
11908 }
11909 else
11910 return value_dependent_expression_p (expression);
11911 }
11912 /* A `sizeof' expression is value-dependent if the operand is
11913 type-dependent. */
11914 if (TREE_CODE (expression) == SIZEOF_EXPR
11915 || TREE_CODE (expression) == ALIGNOF_EXPR)
11916 {
11917 expression = TREE_OPERAND (expression, 0);
11918 if (TYPE_P (expression))
11919 return dependent_type_p (expression);
11920 return type_dependent_expression_p (expression);
11921 }
11922 if (TREE_CODE (expression) == SCOPE_REF)
11923 return dependent_scope_ref_p (expression, value_dependent_expression_p );
11924 if (TREE_CODE (expression) == COMPONENT_REF)
11925 return (value_dependent_expression_p (TREE_OPERAND (expression, 0))
11926 || value_dependent_expression_p (TREE_OPERAND (expression, 1)));
11927 /* A constant expression is value-dependent if any subexpression is
11928 value-dependent. */
11929 if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
11930 {
11931 switch (TREE_CODE_CLASS (TREE_CODE (expression)))
11932 {
11933 case '1':
11934 return (value_dependent_expression_p
11935 (TREE_OPERAND (expression, 0)));
11936 case '<':
11937 case '2':
11938 return ((value_dependent_expression_p
11939 (TREE_OPERAND (expression, 0)))
11940 || (value_dependent_expression_p
11941 (TREE_OPERAND (expression, 1))));
11942 case 'e':
11943 {
11944 int i;
11945 for (i = 0; i < first_rtl_op (TREE_CODE (expression)); ++i)
11946 /* In some cases, some of the operands may be missing.
11947 (For example, in the case of PREDECREMENT_EXPR, the
11948 amount to increment by may be missing.) That doesn't
11949 make the expression dependent. */
11950 if (TREE_OPERAND (expression, i)
11951 && (value_dependent_expression_p
11952 (TREE_OPERAND (expression, i))))
11953 return true;
11954 return false;
11955 }
11956 }
11957 }
11958
11959 /* The expression is not value-dependent. */
11960 return false;
11961 }
从上面规则中导出的 2 个情形值得进一步的考察。在 11922 行, SCOPE_REF 节点的第 0 个操作数是类节点,第 1 个操作数是代表域的节点。例如:它用于保存下面的 A::i (看到这个表达式是值依赖的)。
template <typename T> struct A {
static const int i = sizeof (T);
};
A::i;
而 COMPONENT_REF 的第 0 个操作数是代表对象的节点,第 1 个操作数是代表域的节点。例如:它用于保存下面的 a.i ( a.i 也是值依赖的,因为它以依赖类型来声明的)。
template <typename T> struct A {
T i;
};
template <typename V> void f (A<V>& a, V value) {
a.i = value;
}
对于 SCOPE_REF 节点, dependent_scope_ref_p 验证它是否为依赖。注意到参数 criterion 指向函数 value_dependent_expression_p 。
11816 static bool
11817 dependent_scope_ref_p (tree expression, bool criterion (tree)) in pt.c
11818 {
11819 tree scope;
11820 tree name;
11821
11822 my_friendly_assert (TREE_CODE (expression) == SCOPE_REF, 20030714);
11823
11824 if (!TYPE_P (TREE_OPERAND (expression, 0)))
11825 return true;
11826
11827 scope = TREE_OPERAND (expression, 0);
11828 name = TREE_OPERAND (expression, 1);
11829
11830 /* [temp.dep.expr]
11831
11832 An id-expression is type-dependent if it contains a
11833 nested-name-specifier that contains a class-name that names a
11834 dependent type. */
11835 /* The suggested resolution to Core Issue 2 implies that if the
11836 qualifying type is the current class, then we must peek
11837 inside it. */
11838 if (DECL_P (name)
11839 && currently_open_class (scope)
11840 && !criterion (name))
11841 return false;
11842 if (dependent_type_p (scope))
11843 return true;
11844
11845 return false;
11846 }
考虑 11838 行的条件,以下例为例:
template <typename T> struct A {
int j;
};
当解析类 A 中的成员 j 时,在作用域内 j 不应该被视为类型 / 值依赖,但是从类域外来看却是依赖的。
另外,考虑以下例子:
template <typename T> struct A{
typedef T innerType;
innerType j;
};
A<int>::innerType intType;
A<T>::innerType aType
intType ( A<int>::innerType )不是值依赖的,但 aType ( A<T>::innerType )是。
dependent_type_p_r (continue)
11745 /* -- a template-id in which either the template name is a template
11746 parameter ... */
11747 if (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
11748 return true;
11749 /* ... or any of the template arguments is a dependent type or
11750 an expression that is type-dependent or value-dependent. */
11751 else if (CLASS_TYPE_P (type) && CLASSTYPE_TEMPLATE_INFO (type)
11752 && (any_dependent_template_arguments_p
11753 (INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)))))
11754 return true;
11755
11756 /* All TYPEOF_TYPEs are dependent; if the argument of the `typeof'
11757 expression is not type-dependent, then it should already been
11758 have resolved. */
11759 if (TREE_CODE (type) == TYPEOF_TYPE)
11760 return true;
11761
11762 /* The standard does not specifically mention types that are local
11763 to template functions or local classes, but they should be
11764 considered dependent too. For example:
11765
11766 template <int I> void f() {
11767 enum E { a = I };
11768 S<sizeof (E)> s;
11769 }
11770
11771 The size of `E' cannot be known until the value of `I' has been
11772 determined. Therefore, `E' must be considered dependent. */
11773 scope = TYPE_CONTEXT (type);
11774 if (scope && TYPE_P (scope))
11775 return dependent_type_p (scope);
11776 else if (scope && TREE_CODE (scope) == FUNCTION_DECL)
11777 return type_dependent_expression_p (scope);
11778
11779 /* Other types are non-dependent. */
11780 return false;
11781 }
对于条件“在一个 template-id 中,或者其模板名是一个模板参数,或者其任一实参是一个依赖类型或一个类型依赖或值依赖的表达式 ”,考虑以下例子:
例子 1 :
template <class T> struct Temp {
int t;
};
template <template <class U> class T, typename X, typename V = T<X> > struct A {
V func;
};
int main() {
A<Temp, int> a;
a.func.t = 0;
return 1;
}
类型 Temp 用作缺省实参,它依赖于模板参数 X (这是模板名是模板参数的情形)。
例子 2 :
template <class T> struct Temp {
T t;
};
template<typename T> struct A {
Temp<T> func;
};
int main() {
A<int> a;
a.func.t = 0;
return 1;
}
模板 Temp 作为 A 的成员,接受依赖类型 T 。在这个情形下, Temp 的定义包含了一个层级的模板参数( T )。对于模板相关的树节点,参考图形: 访问模板定义的宏 。它只是检测最里层的模板实参,因为【 3 】 ISO-IE-14882-2003 规定了:
对于一个类模板的成员或一个模板成员,在其一个出现在名字空间作用域的显式特化声明中,该模板成员和其某些封闭类模板可能保持未特化; 除了如果其封闭类模板不被显式特化,该声明不应该显式特化这个类模板成员。在这样的显式特化声明中,在该成员的显式特化声明之前,要提供后跟着模板参数列表的关键字 template ,而不是 template<> 。在模板参数列表中的模板参数的类型,应该与主模板定义中指出的类型一致。 [ 例子: template <class T1> class A { template <class T2> class B { template <class T3> void mf1(T3); void mf2(); }; };
template <> template <class X> class A<int>::B { }; template <> template <> template <class T> void A<int>::B<double>::mf1(T t) { } template <class Y> template <> void A<Y>::B<double>::mf2() { } // ill-formed; B<double> is specialized but // its enclosing class template A is not |
函数 any_dependent_tempalte_arguments_p 可以评估模板参数向量,虽然这里该向量只包含了最里层的实参。
12116 bool
12117 any_dependent_template_arguments_p (tree args) in pt.c
12118 {
12119 int i;
12120 int j;
12121
12122 if (!args)
12123 return false;
12124
12125 for (i = 0; i < TMPL_ARGS_DEPTH (args); ++i)
12126 {
12127 tree level = TMPL_ARGS_LEVEL (args, i + 1);
12128 for (j = 0; j < TREE_VEC_LENGTH (level); ++j)
12129 if (dependent_template_arg_p (TREE_VEC_ELT (level, j)))
12130 return true;
12131 }
12132
12133 return false;
12134 }
检查实参是否有依赖性,与类型声明的检查颇为相似。
12097 static bool
12098 dependent_template_arg_p (tree arg) in pt.c
12099 {
12100 if (!processing_template_decl )
12101 return false;
12102
12103 if (TREE_CODE (arg) == TEMPLATE_DECL
12104 || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
12105 return dependent_template_p (arg);
12106 else if (TYPE_P (arg))
12107 return dependent_type_p (arg);
12108 else
12109 return (type_dependent_expression_p (arg)
12110 || value_dependent_expression_p (arg));
12111 }
这里注意到,只有 TEMPLATE_TEMPLATE_PARM 节点或 TEMPLATE_DECL 节点被 dependent_template_p 处理。看到如果 TEMPLATE_DECL 不是被用作模板参数(即 12153 行的条件不满足)并且它不是在依赖性的作用域中,该 TEMPLATE_DECL 不被认为是依赖性的( ISO-IE-14882-2003 [temp.dep.type] ,在一个 template-id 中,或者其模板名是一个模板参数,或者其任一实参是一个依赖类型或一个类型依赖或值依赖的表达式)。
12138 bool
12139 dependent_template_p (tree tmpl) in pt.c
12140 {
12141 if (TREE_CODE (tmpl) == OVERLOAD)
12142 {
12143 while (tmpl)
12144 {
12145 if (dependent_template_p (OVL_FUNCTION (tmpl)))
12146 return true;
12147 tmpl = OVL_CHAIN (tmpl);
12148 }
12149 return false;
12150 }
12151
12152 /* Template template parameters are dependent. */
12153 if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)
12154 || TREE_CODE (tmpl) == TEMPLATE_TEMPLATE_PARM)
12155 return true;
12156 /* So are names that have not been looked up. */
12157 if (TREE_CODE (tmpl) == SCOPE_REF
12158 || TREE_CODE (tmpl) == IDENTIFIER_NODE)
12159 return true;
12160 /* So are member templates of dependent classes. */
12161 if (TYPE_P (CP_DECL_CONTEXT (tmpl)))
12162 return dependent_type_p (DECL_CONTEXT (tmpl));
12163 return false;
12164 }
看到如果找到的函数模板是重载函数,它是 OVERLOAD 节点,通过 OVL_FUNCTION 封装了 TEMPLATE_DECL ,因此在 12145 行的 dependent_template_p 将找出这个函数模板。
下面特殊节点 unknown_type_node 用作重载函数 / 方法的类型。
type_dependent_expression_p (continue)
12033 if (TREE_TYPE (expression) == unknown_type_node)
12034 {
12035 if (TREE_CODE (expression) == ADDR_EXPR)
12035 return type_dependent_expression_p (TREE_OPERAND (expression, 0));
12037 if (TREE_CODE (expression) == COMPONENT_REF
12038 || TREE_CODE (expression) == OFFSET_REF)
12039 {
12040 if (type_dependent_expression_p (TREE_OPERAND (expression, 0)))
12041 return true;
12042 expression = TREE_OPERAND (expression, 1);
12043 if (TREE_CODE (expression) == IDENTIFIER_NODE)
12044 return false;
12045 }
12046 /* SCOPE_REF with non-null TREE_TYPE is always non-dependent. */
12047 if (TREE_CODE (expression) == SCOPE_REF)
12048 return false;
12049
12050 if (TREE_CODE (expression) == BASELINK)
12051 expression = BASELINK_FUNCTIONS (expression);
12052 if (TREE_CODE (expression) == TEMPLATE_ID_EXPR)
12053 {
12054 if (any_dependent_template_arguments_p
12055 (TREE_OPERAND (expression, 1)))
12056 return true;
12057 expression = TREE_OPERAND (expression, 0);
12058 }
12059 if (TREE_CODE (expression) == OVERLOAD
12060 || TREE_CODE (expression) == FUNCTION_DECL)
12061 {
12062 while (expression)
12063 {
12064 if (type_dependent_expression_p (OVL_CURRENT (expression)))
12065 return true;
12066 expression = OVL_NEXT (expression);
12067 }
12068 return false;
12069 }
12070 abort ();
12071 }
12072
12073 my_friendly_assert (TREE_CODE (expression) != TYPE_DECL, 20051116);
12074
12075 return (dependent_type_p (TREE_TYPE (expression)));
12076 }
上面这段代码继续检查类型的依赖性。注意 12043 行,如果在一个非依赖的作用域中,有未解析的名字,即认为它是非依赖的(除了错误的情况,我想不出合法的情形)。否则,继续 12047 行以下的代码,继续检查这个操作数 1 。