GCC-3.4.6源代码学习笔记(147)

5.13.1.1.2.1.2.          添加模板方法

下面的隐式转换的机制将尝试查是否能隐式地调用某个模板转换操作符。这个过程不能被命令行选项“ –fimiplicit-template ”所关闭。因为该模板函数是隐式调用的,它不能直接地指定模板实参;该模板实参只能根据调用实参推导。而那些不能推导出来的,将不被选中。

在调用点上, ctype 是‘ this ’指针的类型, explicit_targs 是显式模板实参; arglist 是提供的实参;而 return_type 则是对于转换操作符而言理想的类型(或者对于普通的模板函数,它是 NULL )。然后 access_path 是访问该函数的类(这里是‘ this ’指针的类型),而 conversion_path 则是定义该函数的类的 binfo

 

2134 static struct z_candidate *

2135 add_template_candidate (struct z_candidate **candidates, tree tmpl, tree ctype,     in call.c

2136                       tree explicit_targs, tree arglist, tree return_type,

2137                       tree access_path, tree conversion_path, int flags,

2138                       unification_kind_t strict)

2139 {

2140    return

2141      add_template_candidate_real (candidates, tmpl, ctype,

2142                                explicit_targs, arglist, return_type,

2143                                access_path, conversion_path,

2144                                flags, NULL_TREE, strict);

2145 }

 

另外,在这里 strict 对于普通模板函数是 DEDUCE_CALL (或者对于转换操作符,则是 DEDUCE_CONV );并且在下面 add_template_candidate_real 的调用中,把 NULL 传给 obj

 

2035 static struct z_candidate*

2036 add_template_candidate_real (struct z_candidate **candidates, tree tmpl,              in call.c

2037                           tree ctype, tree explicit_targs, tree arglist,

2038                           tree return_type, tree access_path,

2039                           tree conversion_path, int flags, tree obj,

2040                           unification_kind_t strict)

2041 {

2042    int ntparms = DECL_NTPARMS (tmpl);

2043    tree targs = make_tree_vec (ntparms);

2044    tree args_without_in_chrg = arglist;

2045    struct z_candidate *cand;

2046    int i;

2047    tree fn;

2048

2049    /* We don't do deduction on the in-charge parameter, the VTT

2050      parameter or 'this'.  */

2051    if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tmpl))

2052      args_without_in_chrg = TREE_CHAIN (args_without_in_chrg);

2053

2054    if ((DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (tmpl)

2055         || DECL_BASE_CONSTRUCTOR_P (tmpl))

2056        && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (tmpl)))

2057      args_without_in_chrg = TREE_CHAIN (args_without_in_chrg);

2058

2059    i = fn_type_unification (tmpl, explicit_targs, targs,

2060                        args_without_in_chrg,

2061                        return_type, strict, -1);

 

在上面, DECL_NTPARMS 返回 tmpl 的模板形参的个数;相应地, targs 是保存推导出的实参的 vector ;而 args_without_in_chrg ,由其名字所示,将保存除了那些主管参数( in-charge parameter ,即‘ this ’指针, VTT 等)以外的实参。

5.12.4.1.1.2.2.1.    模板实参推导

下面给出了【 3 】的条文 clause 14.8.2 “模板实参推导” [temp.deduct ]

1.  当一个函数模板特化被引用时,所有的模板实参必须具有值。这些值可以,或者被显式指定,或者在一些情形下,从使用处推导出来。 [ 例如:

void f(Array<dcomplex>& cv, Array<int>& ci) {

sort(cv); // call sort(Array<dcomplex>&)

sort(ci); // call sort(Array<int>&)

}

void g(double d) {

int i = convert<int>(d);  // call convert<int,double>(double)

int c = convert<char>(d);  // call convert<char,double>(double)

}

—例子结束 ]

2.  当指定一个显式模板实参列表时,这些模板实参必须与该模板形参列表兼容,并且必须构成下面所描述的一个有效的函数类型;否则类型推导失败。特别地,当就一个给定的函数模板而言,评估一个显式指定的模板实参列表时,要执行以下步骤:

指定的模板实参必须与模板形参在类型上匹配(也就是,类型,非类型,模板),并且实参个数不能多于形参;否则类型推导失败。

非类型实参必须匹配对应非类型模板形参的类型,或者必须能按 14.3.2 所规定的那样转换到对应非类型形参的类型,否则类型推导失败。

在函数模板具现的函数类型中,所有对对应模板形参的引用为指定的模板实参所代替。如果在一个模板形参的替代中,或在函数模板的函数类型的替代中导致一个无效类型,类型推导失败。 [ 注意:异常规范中的等效替代( equivalent substitution )仅当该函数具现后才执行,在那一点上,如果替代导致一个无效的类型,程序是非法的 ] 。类型推导出于以下原因可能失败:

Ø      尝试构建一个元素类型是 void ,或一个函数类型,或一个引用类型的数组,或者尝试构建一个大小为 0 或负的数组。 [ 例如:

template <class T> int f(T[5]);

int I = f<int>(0);   // invalid array

int j = f<void>(0);  // invalid array ]

Ø      尝试在一个限定名( qualified name )中使用一个非类类型。 [ 例如:

template <class T> int f(typename T::B*);

int i = f<int>(0); ]

Ø      尝试使用一个在一个限定名的限定词部分( qualifier portion )中的类型;该限定名命名了一个类型,该类型不包含这个指定的成员,或者该指定的成员不是一个类型,但期望的却是一个类型。 [ 例如:

template <class T> int f(typename T::B*);

struct A {};

struct C { int B; };

int i = f<A>(0);

int j = f<C>(0); ]

Ø      尝试为一个引用类型构建指针。

Ø      尝试为一个引用类型构建引用,或为 void 构建引用。

Ø      尝试构建“ pointer to member of T ”,当 T 不是一个类类型时。 [ 例如:

template <class T> int f(int T::*);

int i = f<int>(0); ]

Ø      尝试在一个模板实参表达式,或在函数声明中使用的表达式中,执行严格非法的转换。 [ 例如:

template <class T, T*> int f(int);

int i2 = f<int,1>(0);  // can’t conv 1 to int* ]

Ø      尝试构建一个具有一个 void 类型参数的函数类型。

Ø      尝试构建一个具有 cv- 限定的函数类型。

3.  在这个替代执行后,执行在 8.3.5 中描述的函数形参类型调整。 [ 例如:一个参数类型“ void () (const int, int[5]) ”变成 void(*) (int,int*) ] [ 注意:在一个函数参数声明中最高层的限定词不会影响该函数类型,但仍然会影响函数内该函数参数变量的类型。—注释结束 ] [ 例如:

template <class T> void f(T t);

template <class X> void g(const X x);

template <class Z> void h(Z, Z*);

int main() {

f<int>(1);  // #1: function type is f(int), t is nonconst

f<const int>(1);  // #2: function type is f(int), t is const

g<int>(1);  // #3: function type is g(int), x is const

g<const int>(1);  // #4: function type is g(int), x is const

h<const int>(1,0);  // #5: function type is h(int, const int*)

}

—例子结束 ] [ 注意: f<int>(1) f<const int>(1) 调用不同的函数,尽管这两个被调用的函数具有相同的函数类型。 注释结束 ]

4.  作为结果的替代及调整后的函数类型被用作用于模板实参推导的函数模板的类型。当所有的模板实参被推导出来后,所有在非推导上下文中模板形参的使用,被替代为对应的推导出的实参值。如果该替代导致一个非法类型,如上所描述,类型推导失败。

5.  除上文所述,一个无效值的使用并不会导致类型推导失败。 [ 例如:在下面的例子中 1000 被转换到 signed char ,并且导致一个如( 4.7 )所描述的依赖实现定义的值。换而言之,两个模板都被顾及,虽然 1000 ,当被转换到 signed char 时,导致一个依赖实现定义的值。

template <int> int f(int);

template <signed char> int f(int);

int i1 = f<1>(0);  // ambiguous

int i2 = f<1000>(0);  // ambiguous

—例子结束 ]

如果模板实参推导成功,下面的函数返回 0

 

8893 int

8894 fn_type_unification (tree fn,                                                                              in pt.c

8895                   tree explicit_targs,

8896                   tree targs,

8897                   tree args,

8898                   tree return_type,

8899                   unification_kind_t strict,

8900                   int len)

8901 {

8902    tree parms;

8903    tree fntype;

8904    int result;

8905

8906    my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);

8907

8908    fntype = TREE_TYPE (fn);

8909    if (explicit_targs)

8910    {

8911      /* [temp.deduct]

8912     

8913        The specified template arguments must match the template

8914        parameters in kind (i.e., type, nontype, template), and there

8915        must not be more arguments than there are parameters;

8916         otherwise type deduction fails.

8917

8918        Nontype arguments must match the types of the corresponding

8919        nontype template parameters, or must be convertible to the

8920        types of the corresponding nontype parameters as specified in

8921        _temp.arg.nontype_, otherwise type deduction fails.

8922

8923        All references in the function type of the function template

8924        to the corresponding template parameters are replaced by the

8925        specified template argument values. If a substitution in a

8926        template parameter or in the function type of the function

8927        template results in an invalid type, type deduction fails.  */

8928      int i;

8929      tree converted_args;

8930      bool incomplete;

8931

8932      if (explicit_targs == error_mark_node)

8933        return 1;

8934

8935      converted_args

8936         = (coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (fn),

8937                                explicit_targs, NULL_TREE, tf_none,

8938                                /*require_all_arguments=*/ 0));

8939      if (converted_args == error_mark_node)

8940        return 1;

8941

8942      /* Substitute the explicit args into the function type. This is

8943        necessary so that, for instance, explicitly declared function

8944        arguments can match null pointed constants. If we were given

8945        an incomplete set of explicit args, we must not do semantic

8946         processing during substitution as we could create partial

8947        instantiations.  */

8948      incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);

8949      processing_template_decl += incomplete;

8950      fntype = tsubst (fntype, converted_args, tf_none, NULL_TREE);

8951      processing_template_decl -= incomplete;

8952       

8953      if (fntype == error_mark_node)

8954        return 1;

8955

8956      /* Place the explicitly specified arguments in TARGS.  */

8957      for (i = NUM_TMPL_ARGS (converted_args); i--;)

8958        TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (converted_args, i);

8959    }

 

参数 explicit_args 是显式模板实参,例如,通过一个 template-id 来提供。我们已经在前一节看过了 coerce_template_parms 的一个例子,它转换显式模板实参来匹配形参,而其结果返回给 8935 行的 converted_arg 。那么在 8950 行的 tsubst 用转换后的实参替代模板形参。

 

fn_type_unification (continue)

 

8961    parms = TYPE_ARG_TYPES (fntype);

8962    /* Never do unification on the 'this' parameter.  */

8963    if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))

8964      parms = TREE_CHAIN (parms);

8965   

8966    if (return_type)

8967    {

8968      /* We've been given a return type to match, prepend it.  */

8969      parms = tree_cons (NULL_TREE, TREE_TYPE (fntype), parms);

8970      args = tree_cons (NULL_TREE, return_type, args);

8971      if (len >= 0)

8972        ++len;

8973    }

8974

8975     /* We allow incomplete unification without an error message here

8976      because the standard doesn't seem to explicitly prohibit it. Our

8977      callers must be ready to deal with unification failures in any

8978      event.  */

8979    result = type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),

8980                             targs, parms, args, /*subr=*/ 0,

8981                             strict, /*allow_incomplete*/ 1, len);

8982

8983    if (result == 0)

8984      /* All is well so far. Now, check:

8985        

8986        [temp.deduct]

8987        

8988        When all template arguments have been deduced, all uses of

8989        template parameters in nondeduced contexts are replaced with

8990        the corresponding deduced argument values. If the

8991        substitution results in an invalid type, as described above,

8992        type deduction fails.  */

8993      if (tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE)

8994               == error_mark_node)

8995        return 1;

8996

8997    return result;

8998 }

 

记住现在正在处理函数模板。

在下面的函数中, tparms 指向模板形参; targs 是保存将在这里得到的推导后的模板实参的 vector (它可能是空的,如果给出了显式模板实参。它包含转换后的这些实参); xparms 是该转换操作符包含返回类型的参数; xargs 是该转换操作符上的 args_without_in_chrg (也就是调用时用户使用的实参),加上期望的返回类型;并且如果 subr 1 ,表示该函数正在被递归调用(来统一一个函数的实参,或一个函数模板的函数形参); allow_incomplete 1 ;并且 xlen -1 ,表示在成功返回前,考虑所有形参;否则就是 xparms 的长度,并考虑这些实参。

 

9113 static int

9114 type_unification_real (tree tparms,                                                                     in pt.c

9115                     tree targs,

9116                    tree xparms,

9117                    tree xargs,

9118                    int subr,

9119                    unification_kind_t strict,

9120                    int allow_incomplete,

9121                    int xlen)

9122 {

9123    tree parm, arg;

9124    int i;

9125    int ntparms = TREE_VEC_LENGTH (tparms);

9126    int sub_strict;

9127    int saw_undeduced = 0;

9128    tree parms, args;

9129    int len;

9130

9131    my_friendly_assert (TREE_CODE (tparms) == TREE_VEC, 289);

9132    my_friendly_assert (xparms == NULL_TREE

9133                     || TREE_CODE (xparms) == TREE_LIST, 290);

9134    my_friendly_assert (!xargs || TREE_CODE (xargs) == TREE_LIST, 291);

9135    my_friendly_assert (ntparms > 0, 292);

9136

9137    switch (strict)

9138    {

9139      case DEDUCE_CALL:

9140        sub_strict = (UNIFY_ALLOW_OUTER_LEVEL | UNIFY_ALLOW_MORE_CV_QUAL

9141                   | UNIFY_ALLOW_DERIVED);

9142        break ;

9143       

9144      case DEDUCE_CONV:

9145        sub_strict = UNIFY_ALLOW_LESS_CV_QUAL;

9146        break ;

9147

9148      case DEDUCE_EXACT:

9149        sub_strict = UNIFY_ALLOW_NONE;

9150        break ;

9151     

9152      case DEDUCE_ORDER:

9153        sub_strict = UNIFY_ALLOW_NONE;

9154        break ;

9155       

9156      default :

9157        abort ();

9158    }

9159

9160    if (xlen == 0)

9161      return 0;

 

参数 strict 是以下之一,而 sub_strict 在上面相应设置之:

Ø         DEDUCE_CALL :正在从一个函数调用中推导实参,如 [temp.deduct.call] 所示。

Ø         DEDUCE_CONV :正在为一个转换函数推导实参,如 [temp.deduct.conv] 所示。

Ø         DEDUCE_EXACT :当执行一个如 [temp.explicit] 所示的显式具现时,当确定一个如 [temp.expl.spec] 所示的显式特化时,或当如 [temp.deduct.funcaddr] 所示提取一个函数模板的地址时,推导实参。

Ø         DEDUCE_ORDER :当计算如 [temp.func.order] [temp.class.order] 所示的类或函数模板特化的偏序( partial ordering )时,推导实参。

 

type_unification_real (continue)

 

9163 again:

9164    parms = xparms;

9165    args = xargs;

9166    len = xlen;

9167

9168    while (parms

9169          && parms != void_list_node

9170          && args

9171          && args != void_list_node)

9172    {

9173      parm = TREE_VALUE (parms);

9174      parms = TREE_CHAIN (parms);

9175      arg = TREE_VALUE (args);

9176      args = TREE_CHAIN (args);

9177

9178      if (arg == error_mark_node)

9179        return 1;

9180      if (arg == unknown_type_node)

9181        /* We can't deduce anything from this, but we might get all the

9182          template args from other function args.  */

9183        continue ;

9184

9185      /* Conversions will be performed on a function argument that

9186        corresponds with a function parameter that contains only

9187        non-deducible template parameters and explicitly specified

9188        template parameters.  */

9189      if (!uses_template_parms (parm))

9190      {

9191        tree type;

9192

9193        if (!TYPE_P (arg))

9194          type = TREE_TYPE (arg);

9195        else

9196          type = arg;

9197

9198        if (same_type_p (parm, type))

9199          continue ;

9200        if (strict != DEDUCE_EXACT

9201           && can_convert_arg (parm, type, TYPE_P (arg) ? NULL_TREE : arg))

9202          continue ;

9203     

9204        return 1;

9205      }

9206     

9207      if (!TYPE_P (arg))

9208      {

9209        my_friendly_assert (TREE_TYPE (arg) != NULL_TREE, 293);

9210        if (type_unknown_p (arg))

9211        {

9212          /* [temp.deduct.type] A template-argument can be deduced from

9213            a pointer to function or pointer to member function

9214            argument if the set of overloaded functions does not

9215            contain function templates and at most one of a set of

9216            overloaded functions provides a unique match.  */

9217

9218          if (resolve_overloaded_unification

9219                (tparms, targs, parm, arg, strict, sub_strict)

9220              != 0)

9221               return 1;

9222          continue ;

9223        }

9224        arg = TREE_TYPE (arg);

9225        if (arg == error_mark_node)

9226          return 1;

9227      }

9228     

9229      {

9230        int arg_strict = sub_strict;

9231         

9232        if (!subr)

9233          arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);

9234

9235        if (unify (tparms, targs, parm, arg, arg_strict))

9236          return 1;

9237      }

9238

9239       /* Are we done with the interesting parms?  */

9240      if (--len == 0)

9241        goto done;

9242    }

 

看到如果形参不依赖于模板参数,就查看实参的类型是否能被隐式地转换到形参的类型,就如同普通函数实参匹配所做的那样。然后如果 arg 具有 unknown_type_node TREE_TYPE ,这可能是某种重载的引用 / 指针(参见下面,它可能是类绑定域中的“ &A::f ”或“ &f ”)。因此通过 resolve_overloaded_unification 尝试按重载处理 arg 。注意,已经查找过的方法应该构建了 BASELINK

 

9281 static int

9282 resolve_overloaded_unification (tree tparms,                                                       in pt.c

9283                             tree targs,

9284                             tree parm,

9285                              tree arg,

9286                             unification_kind_t strict,

9287                             int sub_strict)

9288 {

9289    tree tempargs = copy_node (targs);

9290    int good = 0;

9291    bool addr_p;

9292

9293    if (TREE_CODE (arg) == ADDR_EXPR)

9294    {

9295      arg = TREE_OPERAND (arg, 0);

9296      addr_p = true;

9297    }

9298    else

9299      addr_p = false;

9300

9301    if (TREE_CODE (arg) == COMPONENT_REF)

9302      /* Handle `&x' where `x' is some static or non-static member

9303        function name.  */

9304      arg = TREE_OPERAND (arg, 1);

9305

9306    if (TREE_CODE (arg) == OFFSET_REF)

9307      arg = TREE_OPERAND (arg, 1);

9308

9309    /* Strip baselink information.  */

9310    if (BASELINK_P (arg))

9311      arg = BASELINK_FUNCTIONS (arg);

9312

9313    if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)

9314    {

9315      /* If we got some explicit template args, we need to plug them into

9316        the affected templates before we try to unify, in case the

9317        explicit args will completely resolve the templates in question.  */

9318

9319      tree expl_subargs = TREE_OPERAND (arg, 1);

9320      arg = TREE_OPERAND (arg, 0);

9321

9322      for (; arg; arg = OVL_NEXT (arg))

9323      {

9324        tree fn = OVL_CURRENT (arg);

9325        tree subargs, elem;

9326

9327        if (TREE_CODE (fn) != TEMPLATE_DECL)

9328          continue ;

9329

9330        subargs = get_bindings_overload (fn, DECL_TEMPLATE_RESULT (fn),

9331                                    expl_subargs);

9332        if (subargs)

9333        {

9334          elem = tsubst (TREE_TYPE (fn), subargs, tf_none, NULL_TREE);

9335          good += try_one_overload (tparms, targs, tempargs, parm,

9336                                 elem, strict, sub_strict, addr_p);

9337        }

9338      }

9339    }

9340    else if (TREE_CODE (arg) == OVERLOAD

9341           || TREE_CODE (arg) == FUNCTION_DECL)

9342    {

9343      for (; arg; arg = OVL_NEXT (arg))

9344        good += try_one_overload (tparms, targs, tempargs, parm,

9345                               TREE_TYPE (OVL_CURRENT (arg)),

9346                               strict, sub_strict, addr_p);

9347    }

9348    else

9349      abort ();

9350

9351    /* [temp.deduct.type] A template-argument can be deduced from a pointer

9352      to function or pointer to member function argument if the set of

9353      overloaded functions does not contain function templates and at most

9354      one of a set of overloaded functions provides a unique match.

9355

9356      So if we found multiple possibilities, we return success but don't

9357      deduce anything.  */

9358

9359    if (good == 1)

9360    {

9361      int i = TREE_VEC_LENGTH (targs);

9362      for (; i--; )

9363        if (TREE_VEC_ELT (tempargs, i))

9364          TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (tempargs, i);

9365    }

9366    if (good)

9367      return 0;

9368

9369    return 1;

9370 }

 

在上面的 9313 ,合法的 arg 应该是函数节点,它或者是 OVERLOAD ,或者是 TEMPLATE_EXPR_ID ,或者是 FUNCTION_DECL 。在 TEMPLATE_EXPR_ID 中,其第一个操作数是该函数模板的 TEMPLATE_DECL 节点;第二个操作数,如果不是 NULL ,就是显式实参的 TREE_VEC 。如果该函数模板是重载的,前端遍历这个重载列表,并尝试找到的每个函数模板。在 9330 行,该函数模板的 TEMPLATE_DECL 节点中的 DECL_TEMPLATE_RESULT 是为该对象构建的 *_DECL for object to be created ( 例如, FUNCTION_DECL)

 

10424 static tree

10425 get_bindings_overload (tree fn, tree decl, tree explicit_args)                               in pt.c

10426 {

10427    return get_bindings_real (fn, decl, explicit_args, 0, DEDUCE_EXACT, -1);

10428 }

 

现在 fn 是这个 TEMPLATE_DECL ,而 decl 是关联的 FUNCTION_DECL ,连同 explicit_args 指向显式模板实参。注意到对于所进行的推导,这里使用了 DEDUCE_EXACT 如果成功,这个函数返回推导后的实参。

 

10355 static tree

10356 get_bindings_real (tree fn,                                                                               in pt.c

10357                 tree decl,

10358                 tree explicit_args,

10359                 int check_rettype,

10360                  int deduce,

10361                 int len)

10362 {

10363    int ntparms = DECL_NTPARMS (fn);

10364    tree targs = make_tree_vec (ntparms);

10365    tree decl_type;

10366    tree decl_arg_types;

10367    int i;

10368

10369    /* Substitute the explicit template arguments into the type of DECL.

10370      The call to fn_type_unification will handle substitution into the

10371      FN.  */

10372    decl_type = TREE_TYPE (decl);

10373    if (explicit_args && uses_template_parms (decl_type))

10374    {

10375      tree tmpl;

10376      tree converted_args;

10377

10378      if (DECL_TEMPLATE_INFO (decl))

10379        tmpl = DECL_TI_TEMPLATE (decl);

10380      else

10381        /* We can get here for some invalid specializations.   */

10382        return NULL_TREE;

10383

10384      converted_args

10385         = (coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),

10386                                explicit_args, NULL_TREE,

10387                               tf_none, /*require_all_arguments=*/ 0));

10388      if (converted_args == error_mark_node)

10389        return NULL_TREE;

10390       

10391      decl_type = tsubst (decl_type, converted_args, tf_none, NULL_TREE);

10392      if (decl_type == error_mark_node)

10393        return NULL_TREE;

10394    }

10395

10396    decl_arg_types = TYPE_ARG_TYPES (decl_type);

10397    /* Never do unification on the 'this' parameter.  */

10398    if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))

10399      decl_arg_types = TREE_CHAIN (decl_arg_types);

10400

10401    i = fn_type_unification (fn, explicit_args, targs,

10402                        decl_arg_types,

10403                         (check_rettype || DECL_CONV_FN_P (fn)

10404                                      ? TREE_TYPE (decl_type) : NULL_TREE),

10405                        deduce, len);

10406

10407    if (i != 0)

10408      return NULL_TREE;

10409

10410    return targs;

10411 }

 

10379 行, DECL_TI_TEMPLATE 返回由 decl 具现或特化的 TEMPLATE_DECL 。这个 TEMPLATE_DECL 将是直接父亲( immediate parent ),但不是最泛化模板( the most general template )。例如,在:

template <class T> struct S { template <class U> void f(U); }

S<int>::f<double> ’的 FUNCTION_DECL ,作为其 DECL_TI_TEMPLATE ,具有‘ template <class U> S<int>::f<U> ’。

作为一个特例,对于一个类模板的一个成员友元模板,这个值将不会是一个 TEMPLATE_DECL ,而是一个表示该模板名及提供的显式模板实参的 IDENTIFIER_NODE OVERLOAD 。例如,在:

template <class T> struct S { friend void f<int>(int, double); }

DECL_TI_TEMPLATE 将是‘ f ’的 IDENTIFIER_NODE

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值