📄 pt.c
字号:
turns out to be a specialization: template <class T> void foo(T); class S { friend void foo<>(int) }; template <> void foo(int); We transform the existing DECL in place so that any pointers to it become pointers to the updated declaration. If there was a definition for the template, but not for the specialization, we want this to look as if there is no definition, and vice versa. */ DECL_INITIAL (fn) = NULL_TREE; duplicate_decls (spec, fn); return fn; } } else if (DECL_TEMPLATE_SPECIALIZATION (fn)) { duplicate_decls (spec, fn); return fn; } } } DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = perm_tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl)); return spec;}/* Unregister the specialization SPEC as a specialization of TMPL. Returns nonzero if the SPEC was listed as a specialization of TMPL. */static intunregister_specialization (spec, tmpl) tree spec; tree tmpl;{ tree* s; for (s = &DECL_TEMPLATE_SPECIALIZATIONS (tmpl); *s != NULL_TREE; s = &TREE_CHAIN (*s)) if (TREE_VALUE (*s) == spec) { *s = TREE_CHAIN (*s); return 1; } return 0;}/* Print the list of candidate FNS in an error message. */voidprint_candidates (fns) tree fns;{ tree fn; const char *str = "candidates are:"; for (fn = fns; fn != NULL_TREE; fn = TREE_CHAIN (fn)) { tree f; for (f = TREE_VALUE (fn); f; f = OVL_NEXT (f)) cp_error_at ("%s %+#D", str, OVL_CURRENT (f)); str = " "; }}/* Returns the template (one of the functions given by TEMPLATE_ID) which can be specialized to match the indicated DECL with the explicit template args given in TEMPLATE_ID. The DECL may be NULL_TREE if none is available. In that case, the functions in TEMPLATE_ID are non-members. If NEED_MEMBER_TEMPLATE is non-zero the function is known to be a specialization of a member template. The template args (those explicitly specified and those deduced) are output in a newly created vector *TARGS_OUT. If it is impossible to determine the result, an error message is issued. The error_mark_node is returned to indicate failure. */static treedetermine_specialization (template_id, decl, targs_out, need_member_template) tree template_id; tree decl; tree* targs_out; int need_member_template;{ tree fn; tree fns; tree targs; tree explicit_targs; tree candidates = NULL_TREE; tree templates = NULL_TREE; *targs_out = NULL_TREE; if (template_id == error_mark_node) return error_mark_node; fns = TREE_OPERAND (template_id, 0); explicit_targs = TREE_OPERAND (template_id, 1); if (fns == error_mark_node) return error_mark_node; /* Check for baselinks. */ if (TREE_CODE (fns) == TREE_LIST) fns = TREE_VALUE (fns); for (; fns; fns = OVL_NEXT (fns)) { tree tmpl; fn = OVL_CURRENT (fns); if (TREE_CODE (fn) == TEMPLATE_DECL) /* DECL might be a specialization of FN. */ tmpl = fn; else if (need_member_template) /* FN is an ordinary member function, and we need a specialization of a member template. */ continue; else if (TREE_CODE (fn) != FUNCTION_DECL) /* We can get IDENTIFIER_NODEs here in certain erroneous cases. */ continue; else if (!DECL_FUNCTION_MEMBER_P (fn)) /* This is just an ordinary non-member function. Nothing can be a specialization of that. */ continue; else { tree decl_arg_types; /* This is an ordinary member function. However, since we're here, we can assume it's enclosing class is a template class. For example, template <typename T> struct S { void f(); }; template <> void S<int>::f() {} Here, S<int>::f is a non-template, but S<int> is a template class. If FN has the same type as DECL, we might be in business. */ if (!same_type_p (TREE_TYPE (TREE_TYPE (decl)), TREE_TYPE (TREE_TYPE (fn)))) /* The return types differ. */ continue; /* Adjust the type of DECL in case FN is a static member. */ decl_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl)); if (DECL_STATIC_FUNCTION_P (fn) && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) decl_arg_types = TREE_CHAIN (decl_arg_types); if (compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), decl_arg_types)) /* They match! */ candidates = tree_cons (NULL_TREE, fn, candidates); continue; } /* See whether this function might be a specialization of this template. */ targs = get_bindings (tmpl, decl, explicit_targs); if (!targs) /* We cannot deduce template arguments that when used to specialize TMPL will produce DECL. */ continue; /* Save this template, and the arguments deduced. */ templates = scratch_tree_cons (targs, tmpl, templates); } if (templates && TREE_CHAIN (templates)) { /* We have: [temp.expl.spec] It is possible for a specialization with a given function signature to be instantiated from more than one function template. In such cases, explicit specification of the template arguments must be used to uniquely identify the function template specialization being specialized. Note that here, there's no suggestion that we're supposed to determine which of the candidate templates is most specialized. However, we, also have: [temp.func.order] Partial ordering of overloaded function template declarations is used in the following contexts to select the function template to which a function template specialization refers: -- when an explicit specialization refers to a function template. So, we do use the partial ordering rules, at least for now. This extension can only serve to make illegal programs legal, so it's safe. And, there is strong anecdotal evidence that the committee intended the partial ordering rules to apply; the EDG front-end has that behavior, and John Spicer claims that the committee simply forgot to delete the wording in [temp.expl.spec]. */ tree tmpl = most_specialized (templates, decl, explicit_targs); if (tmpl && tmpl != error_mark_node) { targs = get_bindings (tmpl, decl, explicit_targs); templates = scratch_tree_cons (targs, tmpl, NULL_TREE); } } if (templates == NULL_TREE && candidates == NULL_TREE) { cp_error_at ("template-id `%D' for `%+D' does not match any template declaration", template_id, decl); return error_mark_node; } else if ((templates && TREE_CHAIN (templates)) || (candidates && TREE_CHAIN (candidates)) || (templates && candidates)) { cp_error_at ("ambiguous template specialization `%D' for `%+D'", template_id, decl); chainon (candidates, templates); print_candidates (candidates); return error_mark_node; } /* We have one, and exactly one, match. */ if (candidates) { /* It was a specialization of an ordinary member function in a template class. */ *targs_out = copy_node (DECL_TI_ARGS (TREE_VALUE (candidates))); return DECL_TI_TEMPLATE (TREE_VALUE (candidates)); } /* It was a specialization of a template. */ targs = DECL_TI_ARGS (DECL_RESULT (TREE_VALUE (templates))); if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (targs)) { *targs_out = copy_node (targs); SET_TMPL_ARGS_LEVEL (*targs_out, TMPL_ARGS_DEPTH (*targs_out), TREE_PURPOSE (templates)); } else *targs_out = TREE_PURPOSE (templates); return TREE_VALUE (templates);} /* Check to see if the function just declared, as indicated in DECLARATOR, and in DECL, is a specialization of a function template. We may also discover that the declaration is an explicit instantiation at this point. Returns DECL, or an equivalent declaration that should be used instead if all goes well. Issues an error message if something is amiss. Returns error_mark_node if the error is not easily recoverable. FLAGS is a bitmask consisting of the following flags: 2: The function has a definition. 4: The function is a friend. The TEMPLATE_COUNT is the number of references to qualifying template classes that appeared in the name of the function. For example, in template <class T> struct S { void f(); }; void S<int>::f(); the TEMPLATE_COUNT would be 1. However, explicitly specialized classes are not counted in the TEMPLATE_COUNT, so that in template <class T> struct S {}; template <> struct S<int> { void f(); } template <> void S<int>::f(); the TEMPLATE_COUNT would be 0. (Note that this declaration is illegal; there should be no template <>.) If the function is a specialization, it is marked as such via DECL_TEMPLATE_SPECIALIZATION. Furthermore, its DECL_TEMPLATE_INFO is set up correctly, and it is added to the list of specializations for that template. */treecheck_explicit_specialization (declarator, decl, template_count, flags) tree declarator; tree decl; int template_count; int flags;{ int have_def = flags & 2; int is_friend = flags & 4; int specialization = 0; int explicit_instantiation = 0; int member_specialization = 0; tree ctype = DECL_CLASS_CONTEXT (decl); tree dname = DECL_NAME (decl); if (processing_specialization) { /* The last template header was of the form template <>. */ if (template_header_count > template_count) { /* There were more template headers than qualifying template classes. */ if (template_header_count - template_count > 1) /* There shouldn't be that many template parameter lists. There can be at most one parameter list for every qualifying class, plus one for the function itself. */ cp_error ("too many template parameter lists in declaration of `%D'", decl); SET_DECL_TEMPLATE_SPECIALIZATION (decl); if (ctype) member_specialization = 1; else specialization = 1; } else if (template_header_count == template_count) { /* The counts are equal. So, this might be a specialization, but it is not a specialization of a member template. It might be something like template <class T> struct S { void f(int i); }; template <> void S<int>::f(int i) {} */ specialization = 1; SET_DECL_TEMPLATE_SPECIALIZATION (decl); } else { /* This cannot be an explicit specialization. There are not enough headers for all of the qualifying classes. For example, we might have: template <> void S<int>::T<char>::f(); But, we're missing another template <>. */ cp_error("too few template parameter lists in declaration of `%D'", decl); return decl; } } else if (processing_explicit_instantiation) { if (template_header_count) cp_error ("template parameter list used in explicit instantiation"); if (have_def) cp_error ("definition provided for explicit instantiation"); explicit_instantiation = 1; } else if (ctype != NULL_TREE && !TYPE_BEING_DEFINED (ctype) && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype) && !is_friend) { /* This case catches outdated code that looks like this: template <class T> struct S { void f(); }; void S<int>::f() {} // Missing template <> We disable this check when the type is being defined to avoid complaining about default compiler-generated constructors, destructors, and assignment operators. Since the type is an instantiation, not a specialization, these are the only functions that can be defined before the class is complete. */ /* If they said template <class T> void S<int>::f() {} that's bogus. */ if (template_header_count) { cp_error ("template parameters specified in specialization"); return decl; } if (pedantic) cp_pedwarn ("explicit specialization not preceded by `template <>'"); specialization = 1; SET_DECL_TEMPLATE_SPECIALIZATION (decl); } else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) { if (is_friend) /* This could be something like: template <class T> void f(T); class S { friend void f<>(int); } */ specialization = 1; else { /* This case handles bogus declarations like template <> template <class T> void f<int>(); */ cp_error ("template-id `%D' in declaration of primary template", declarator); return decl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -