Studying note of GCC-3.4.6 source (147 - cont 1)

Then if everything goes smoothly, it finally puts deduced arguments into targs at line 10401 by fn_type_unifcation . And these arguments are then subsistituted into the template parameters by tsubst immediately at line 9334 in resolve_overloaded_unification .

Next in below function, tparms refers to the template parameters; orig_targs is the vector for the deduced arguments; and both are arguments tparms and targs of the caller -- resolve_overloaded_unification and unchanged throughout the procedure. But targs is the copied of orig_tags ; parm is the template parameter being unified; arg is the corresponding template argument (here they should be pointer-to-function/method); and addr_p if true indicates seeing “&”.

 

9380 static int

9381 try_one_overload (tree tparms,                                                                          in pt.c

9382                 tree orig_targs,

9383                 tree targs,

9384                 tree parm,

9385                 tree arg,

9386                 unification_kind_t strict,

9387                 int sub_strict,

9388                 bool addr_p)

9389 {

9390    int nargs;

9391    tree tempargs;

9392    int i;

9393

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

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

9396      overloaded functions does not contain function templates and at most

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

9398

9399      So if this is a template, just return success.  */

9400

9401    if (uses_template_parms (arg))

9402      return 1;

9403

9404    if (TREE_CODE (arg) == METHOD_TYPE)

9405      arg = build_ptrmemfunc_type (build_pointer_type (arg));

9406    else if (addr_p)

9407      arg = build_pointer_type (arg);

9408

9409    sub_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);

 

Note that when using template parameter of pointer-to-function or pointer-to-method, we only can uses “&A::f” or “&f” (for function, even can use “f”) and the typedef aliases as the argument, because the front-end requires compile time constant. So above, after seeing such structure, it builds the corresponding pointer.

In [3], [temp.deduct.conv] defines that “Template argument deduction is done by comparing the return type of the template conversion function (call it P) with the type that is required as the result of the conversion (call it A) as described in 14.8.2.4.

And [temp.deduct.call] says: “Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below.

Remember that for conversion operator, it has pushes the returned type of the operator into the parameters list, and the desired type into the argument list. And see that at call of the operator, it will   try to convert returned type into the desired type (that is performed from parameter to argument instead of from argument to parameter for function parameters). So below function at first swaps these two variables via DEDUCE_CONV (now P becomes A, A becomes P for rule of conversion operator). Further [3] defines:

from [temp.deduct.call]

2.  If P is not a reference type:

— If A is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is used in place of A for type deduction; otherwise,

— If A is a function type, the pointer type produced by the function-to-pointer standard conversion (4.3) is used in place of A for type deduction; otherwise,

— If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction.

If P is a cv-qualified type, the top level cv-qualifiers of P’s type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction.

from [temp.deduct.conv]

2.  If A is not a reference type:

— If P is an array type, the pointer type produced by the array-to-pointer standard conversion (4.2) is used in place of P for type deduction; otherwise,

— If P is a function type, the pointer type produced by the function-to-pointer standard conversion (4.3) is used in place of P for type deduction; otherwise,

— If P is a cv-qualified type, the top level cv-qualifiers of P’s type are ignored for type deduction.

If A is a cv-qualified type, the top level cv-qualifiers of A’s type are ignored for type deduction. If A is a reference type, the type referred to by A is used for type deduction.

from [temp.deduct.call]

3.  In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above). However, there are three cases that allow a difference:

— If the original P is a reference type, the deduced A (i.e., the type referred to by the reference) can be more cv-qualified than A.

— A can be another pointer or pointer to member type that can be converted to the deduced A via a qualification conversion (4.4).

— If P is a class, and P has the form template-id, then A can be a derived class of the deduced A. Likewise, if P is a pointer to a class of the form template-id, A can be a pointer to a derived class pointed to by the deduced A.

These alternatives are considered only if type deduction would otherwise fail. If they yield more than one possible deduced A, the type deduction fails. [Note: if a template-parameter is not used in any of the function parameters of a function template, or is used only in a non-deduced context, its corresponding template-argument cannot be deduced from a function call and the template-argument must be explicitly specified.]

from [temp.deduct.conv]

3.  In general, the deduction process attempts to find template argument values that will make the deduced A identical to A. However, there are two cases that allow a difference:

— If the original A is a reference type, A can be more cv-qualified than the deduced A (i.e., the type referred to by the reference)

— The deduced A can be another pointer or pointer to member type that can be converted to A via a qualification conversion.

These alternatives are considered only if type deduction would otherwise fail. If they yield more than one possible deduced A, the type deduction fails.

See that by swapping arg with parm , it can use the second rule of [temp.deduct.call] for both cases without any change. While for the third rule of [temp.deduct.call] and [temp.deduct.conv], they say following examples:

Example 1:

template <class T> void func (const T&);           // const T& is P

int a;

main () { func (a); }              // const int is deduced A, and A is int

Example 2:

template <typename T> class A {

public :

T i;

operator T& () { return i; }

// operator const T& () { return i; } // const int& is P (A after swap) in A<int> a

};

void func (const int&) {}              // const int& is A (P after swap)

// void func (int&) {}     // int& is A (P after swap)

main () {

  A<int> a;     // int& is P (A after swap)

func (a);      // int is deduced A, const int is deduced A for commented out operator

}

Statements commented out above if restored, will cause error of conflicts in cv-qualification. It can see that by swapping parm and arg for conversion operator, we can safely use first two alternatives in rule 3 for deducing function call for both cases. While for the third alternative in rule 3 for function call, the front-end can close it without setting bit UNIFY_ALLOW_DERIVED for conversion operator.

 

9007 static int

9008 maybe_adjust_types_for_deduction (unification_kind_t strict,                               in pt.c

9009                                tree* parm,

9010                                tree* arg)

9011 {

9012    int result = 0;

9013   

9014    switch (strict)

9015    {

9016      case DEDUCE_CALL:

9017        break ;

9018

9019      case DEDUCE_CONV:

9020      {

9021        /* Swap PARM and ARG throughout the remainder of this

9022          function; the handling is precisely symmetric since PARM

9023          will initialize ARG rather than vice versa.  */

9024        tree* temp = parm;

9025        parm = arg;

9026        arg = temp;

9027        break ;

9028      }

9029

9030      case DEDUCE_EXACT:

9031        /* There is nothing to do in this case.  */

9032        return 0;

9033

9034      case DEDUCE_ORDER:

9035         /* DR 214. [temp.func.order] is underspecified, and leads to no

9036          ordering between things like `T *' and `T const &' for `U *'.

9037          The former has T=U and the latter T=U*. The former looks more

9038          specialized and John Spicer considers it well-formed (the EDG

9039          compiler accepts it).

9040

9041          John also confirms that deduction should proceed as in a function

9042          call. Which implies the usual ARG and PARM conversions as DEDUCE_CALL.

9043          However, in ordering, ARG can have REFERENCE_TYPE, but no argument

9044          to an actual call can have such a type.

9045          

9046          If both ARG and PARM are REFERENCE_TYPE, we change neither.

9047          If only ARG is a REFERENCE_TYPE, we look through that and then

9048          proceed as with DEDUCE_CALL (which could further convert it).  */

9049        if (TREE_CODE (*arg) == REFERENCE_TYPE)

9050        {

9051          if (TREE_CODE (*parm) == REFERENCE_TYPE)

9052            return 0;

9053           *arg = TREE_TYPE (*arg);

9054        }

9055        break ;

9056      default :

9057        abort ();

9058    }

9059

9060    if (TREE_CODE (*parm) != REFERENCE_TYPE)

9061    {

9062       /* [temp.deduct.call]

9063   

9064        If P is not a reference type:

9065   

9066        --If A is an array type, the pointer type produced by the

9067         array-to-pointer standard conversion (_conv.array_) is

9068         used in place of A for type deduction; otherwise,

9069   

9070        --If A is a function type, the pointer type produced by

9071         the function-to-pointer standard conversion

9072         (_conv.func_) is used in place of A for type deduction;

9073         otherwise,

9074   

9075        --If A is a cv-qualified type, the top level

9076         cv-qualifiers of A's type are ignored for type

9077         deduction.  */

9078      if (TREE_CODE (*arg) == ARRAY_TYPE)

9079        *arg = build_pointer_type (TREE_TYPE (*arg));

9080      else if (TREE_CODE (*arg) == FUNCTION_TYPE)

9081        *arg = build_pointer_type (*arg);

9082      else

9083        *arg = TYPE_MAIN_VARIANT (*arg);

9084    }

9085   

9086    /* [temp.deduct.call]

9087      

9088      If P is a cv-qualified type, the top level cv-qualifiers

9089      of P's type are ignored for type deduction. If P is a

9090      reference type, the type referred to by P is used for

9091      type deduction.  */

9092    *parm = TYPE_MAIN_VARIANT (*parm);

9093    if (TREE_CODE (*parm) == REFERENCE_TYPE)

9094     {

9095      *parm = TREE_TYPE (*parm);

9096      result |= UNIFY_ALLOW_OUTER_MORE_CV_QUAL;

9097    }

9098

9099     /* DR 322. For conversion deduction, remove a reference type on parm

9100      too (which has been swapped into ARG).  */

9101    if (strict == DEDUCE_CONV && TREE_CODE (*arg) == REFERENCE_TYPE)

9102      *arg = TREE_TYPE (*arg);

9103   

9104    return result;

9105 }

 

So function maybe_adjust_types_for_deduction converts argument of the template following rule in above table specified by [3]. Comment at line 9035 mentions a flaw in [3], and gives out a possible solution adopted by EDG (the best C++ front-end).

 

try_one_overload (continue)

 

9411    /* We don't copy orig_targs for this because if we have already deduced

9412      some template args from previous args, unify would complain when we

9413      try to deduce a template parameter for the same argument, even though

9414      there isn't really a conflict.  */

9415    nargs = TREE_VEC_LENGTH (targs);

9416    tempargs = make_tree_vec (nargs);

9417

9418     if (unify (tparms, tempargs, parm, arg, sub_strict) != 0)

9419      return 0;

 

In [3], clause 14.8.2.4 “Deducing template arguments from a type” are given as below [temp.deduct.type ] :

1.  Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values (a type for a type parameter, a value for a non-type parameter, or a template for a template parameter) that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.

2.  In some cases, the deduction is done using a single set of types P and A, in other cases, there will be a set of corresponding types P and A. Type deduction is done independently for each P/A pair, and the deduced template argument values are then combined. If type deduction cannot be done for any P/A pair, or if for any pair the deduction leads to more than one possible set of deduced values, or if different pairs yield different deduced values, or if any template argument remains neither deduced nor explicitly specified, template argument deduction fails.

3.  A given type P can be composed from a number of other types, templates, and non-type values:

A function type includes the types of each of the function parameters and the return type.

A pointer to member type includes the type of the class object pointed to and the type of the member pointed to.

A type that is a specialization of a class template (e.g., A<int>) includes the types, templates, and non-type values referenced by the template argument list of the specialization.

An array type includes the array element type and the value of the array bound.

In most cases, the types, templates, and non-type values that are used to compose P participate in template argument deduction. That is, they may be used to determine the value of a template argument, and the value so determined must be consistent with the values determined elsewhere. In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in nondeduced contexts and is not explicitly specified, template argument deduction fails.

4.  The nondeduced contexts are:

The nested-name-specifier of a type that was specified using a qualified-id.

A type that is a template-id in which one or more of the template-arguments is an expression that references a template-parameter.

When a type name is specified in a way that includes a nondeduced context, all of the types that comprise that type name are also nondeduced. However, a compound type can include both deduced and nondeduced types. [Example: If a type is specified as A<T>::B<T2>, both T and T2 are nondeduced.  Likewise, if a type is specified as A<I+J>::X<T>, I, J, and T are nondeduced. If a type is specified as void f(typename A<T>::B, A<T>), the T in A<T>::B is nondeduced but the T in A<T>is deduced. ]

5.  [Example: Here is an example in which different parameter/argument pairs produce inconsistent template argument deductions:

template <class T> void f(T x, T y) { /* ... */ }

struct A { /* ... */ };

struct B : A { /* ... */ };

int g(A a, B b) {

f(a,b); // error: T could be A or B

f(b,a); // error: T could be A or B

f(a,a); // OK: T is A

f(b,b); // OK: T is B

}

6.  Here is an example where two template arguments are deduced from a single function parameter/argument pair. This can lead to conflicts that cause type deduction to fail:

template <class T, class U> void f(T (*) (T, U, U) );

int g1( int, float, float);

char g2( int, float, float);

int g3( int, char, float);

void r() {

f(g1); // OK: T is int and U is float

f(g2); // error: T could be char or int

f(g3); // error: U could be char or float

}

7.  Here is an example where a qualification conversion applies between the argument type on the function call and the deduced template argument type:

template <class T> void f(const T*) {}

int *p;

void s() {

f(p); // f(const int *)

}

8.  Here is an example where the template argument is used to instantiate a derived class type of the corresponding function parameter type:

template <class T> struct B { };

template <class T> struct D : public B<T> {};

struct D2 : public B<int> {};

template <class T> void f(B<T>&){}

void t() {

D<int> d;

D2 d2;

f(d); // calls f(B<int>&)

f(d2); // calls f(B<int>&)

}

end example]

9.  A template type argument T, a template template argument TT or a template non-type argument i can be deduced if P and A have one of the following forms:

T

cv-list T

T*

T&

T[integer-constant]

template-name<T> (where template-name refers to a class template)

type(*)(T)

T(*)()

T(*)(T)

T type::*

type T::*

T T::*

T (type::*)()

type (T::*)()

type (type::*)(T)

type (T::*)(T)

T (type::*)(T)

T (T::*)()

T (T::*)(T)

type[i]

template-name<i> (where template-name refers to a class template)

TT<T>

TT<i>

TT<>

where (T) represents argument lists where at least one argument type contains a T, and () represents argument lists where no parameter contains a T. Similarly, <T> represents template argument lists where at least one argument contains a T, <i> represents template argument lists where at least one argument contains an i and <> represents template argument lists where no argument contains a T or an i.

10. These forms can be used in the same way as T is for further composition of types. [Example:

X<int> (*)(char[6])

is of the form

template-name<T> (*)(type[i])

which is a variant of

type (*)(T)

where type is X<int> and T is char[6]. ]

11. Template arguments cannot be deduced from function arguments involving constructs other than the ones specified above.

12. A template type argument cannot be deduced from the type of a non-type template-argument. [Example:

template <class T, T i> void f(double a[10][i]);

int v[10][20];

f(v); // error: argument for template-parameter T cannot be deduced

end example]

13. [Note: except for reference and pointer types, a major array bound is not part of a function parameter type and cannot be deduced from an argument:

template <int i> void f1(int a[10][i]);

template <int i> void f2(int a[i][20]);

template <int i> void f3(int (&a)[i][20]);

void g() {

int v[10][20];

f1(v); // OK: i deduced to be 20

f1<20>(v); // OK

f2(v); // error: cannot deduce template-argument i

f2<10>(v); // OK

f3(v); // OK: i deduced to be 10

}

14. If, in the declaration of a function template with a non-type template-parameter, the non-type template-parameter is used in an expression in the function parameter-list, the corresponding template-argument must always be explicitly specified or deduced elsewhere because type deduction would otherwise always fail for such a template-argument.

template <int i> class A { /* ... */ };

template <short s> void g(A<s+1>);

void k() {

A<1> a;

g(a); // error: deduction fails for expression s+1

g<0>(a); // OK

}

end note] [Note: template parameters do not participate in template argument deduction if they are used only in nondeduced contexts. For example,

template <int i, typename T>

T deduce(typename A<T>::X x,  // T is not deduced here

T t, // but T is deduced here

typename B<i>::Y y);   // i is not deduced here

A<int> a;

B<77> b;

int x = deduce<77>(a.xm, 62, y.ym);

// T is deduced to be int, a.xm must be convertible to A<int>::X

// i is explicitly specified to be 77, y.ym must be convertible to B<77>::Y

end note]

15. If, in the declaration of a function template with a non-type template-parameter, the non-type template-parameter is used in an expression in the function parameter-list and, if the corresponding template-argument is deduced, the template-argument type shall match the type of the template-parameter exactly (Although the template-argument corresponding to a template-parameter of type bool may be deduced from an array bound, the resulting value will always be true because the array bound will be non-zero.) [Example: except that a template-argument deduced from an array bound may be of any integral type.

template <int i> class A { /* ... */ };

template <short s> void f(A<s>);

void k1() {

A<1> a;

f(a); // error: deduction fails for conversion from int to short

f<1>(a); // OK

}

template <const short cs> class B { };

template <short s> void g(B<s>);

void k2() {

B<1> b;

g(b); // OK: cv-qualifiers are ignored on template parameter types

}

end example]

16. A template-argument can be deduced from a pointer to function or pointer to member function argument if the set of overloaded functions does not contain function templates and at most one of a set of overloaded functions provides a unique match. [Example:

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

template <class T> void foo(T,int);

void g(int,int);

void g(char,int);

void h(int,int,int);

void h(char,int);

int m() {

f(&g); // error: ambiguous

f(&h); // OK: void h(char,int) is a unique match

f(&foo); // error: type deduction fails because foo is a template

}

end example]

17. A template type-parameter cannot be deduced from the type of a function default argument. [Example:

template <class T> void f(T = 5, T = 7);

void g() {

f(1); // OK: call f<int>(1,7)

f(); // error: cannot deduce T

f<int>(); // OK: call f<int>(5,7)

}

end example]

18. The template-argument corresponding to a template template-parameter is deduced from the type of the template-argument of a class template specialization used in the argument list of a function call. [Example:

template <template <class T> class X> struct A { };

template <template <class T> class X> void f(A<X>) { }

template <class T> struct B { };

A<B> ab;

f(ab); // calls f(A<B>)

end example] [Note: a default template-argument cannot be specified in a function template declaration or definition; therefore default template-arguments cannot be used to influence template argument deduction. ]

Here unify does the real deduction and returns 0 if successes, in which argument tparms is the template parameters of the template in interesting (it is readonly here); targs is the vector to hold the deduced argument (see it is the fresh new empty vector tempargs above. As every unify call would deduce a pair of parameter/argument, and try_one_overload also uses unify to deduce pointer-to-function pair, thus unify must be recursed; thus the function needs merge result of current deduction into targs ); arg is the argument being deduced; and parm is the corresponding parameter.

The parameter strict is a bitwise or of the following flags:

Ÿ           UNIFY_ALLOW_NONE: Require an exact match between PARM and ARG.

Ÿ           UNIFY_ALLOW_MORE_CV_QUAL: Allow the deduced ARG to be more cv-qualified (by qualification conversion) than ARG.

Ÿ           UNIFY_ALLOW_LESS_CV_QUAL: Allow the deduced ARG to be less cv-qualified than ARG.

Ÿ           UNIFY_ALLOW_DERIVED: Allow the deduced ARG to be a template base class of ARG, or a pointer to a template base class of the type pointed to by ARG.

Ÿ           UNIFY_ALLOW_INTEGER: Allow any integral type to be deduced. See the TEMPLATE_PARM_INDEX case for more information.

Ÿ           UNIFY_ALLOW_OUTER_LEVEL: This is the outermost level of a deduction. Used to determine validity of qualification conversions. A valid qualification conversion must have const qualified pointers leading up to the inner type which requires additional CV quals, except at the outer level, where const is not required [conv.qual]. It would be normal to set this flag in addition to setting UNIFY_ALLOW_MORE_CV_QUAL.

Ÿ           UNIFY_ALLOW_OUTER_MORE_CV_QUAL: This is the outermost level of a deduction, and PARM can be more CV qualified at this point.

Ÿ           UNIFY_ALLOW_OUTER_LESS_CV_QUAL: This is the outermost level of a deduction, and PARM can be less CV qualified at this point.

Ÿ           UNIFY_ALLOW_MAX_CORRECTION: This is an INTEGER_TYPE's maximum value. Used if the range may have been derived from a size specification, such as an array size. If the size was given by a nontype template parameter N, the maximum value will have the form N-1. The flag says that we can (and indeed must) unify N with (ARG + 1), an exception to the normal rules on folding PARM.

 

9735 static int

9736 unify (tree tparms, tree targs, tree parm, tree arg, int strict)                                 in pt.c

9737 {

9738    int idx;

9739    tree targ;

9740    tree tparm;

9741    int strict_in = strict;

9742

9743    /* I don't think this will do the right thing with respect to types.

9744      But the only case I've seen it in so far has been array bounds, where

9745      signedness is the only information lost, and I think that will be

9746      okay.  */

9747    while (TREE_CODE (parm) == NOP_EXPR)

9748      parm = TREE_OPERAND (parm, 0);

9749

9750    if (arg == error_mark_node)

9751      return 1;

9752    if (arg == unknown_type_node)

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

9754        template args from other function args.  */

9755      return 0;

9756

9757    /* If PARM uses template parameters, then we can't bail out here,

9758      even if ARG == PARM, since we won't record unifications for the

9759      template parameters. We might need them if we're trying to

9760      figure out which of two things is more specialized.  */

9761    if (arg == parm && !uses_template_parms (parm))

9762      return 0;

9763

9764    /* Immediately reject some pairs that won't unify because of

9765      cv-qualification mismatches.  */

9766    if (TREE_CODE (arg) == TREE_CODE (parm)

9767        && TYPE_P (arg)

9768        /* It is the elements of the array which hold the cv quals of an array

9769          type, and the elements might be template type parms. We'll check

9770          when we recurse.  */

9771        && TREE_CODE (arg) != ARRAY_TYPE

9772        /* We check the cv-qualifiers when unifying with template type

9773          parameters below. We want to allow ARG `const T' to unify with

9774          PARM `T' for example, when computing which of two templates

9775          is more specialized, for example.  */

9776        && TREE_CODE (arg) != TEMPLATE_TYPE_PARM

9777        && !check_cv_quals_for_unify (strict_in, arg, parm))

9778      return 1;

 

Line 9764 to 9778 as comment says reject some pairs dues to mismatched cv-qualification. See here we need be conservative, only template parameter and with argument of the same code would be considered. Here filters out ARRAY_TYPE and TEMPLATE_TYPE_PARM (stands for template   type parameter like ‘T’), as they need be processed specially in below.

 

9659 static int

9660 check_cv_quals_for_unify (int strict, tree arg, tree parm)                                           in pt.c

9661 {

9662    int arg_quals = cp_type_quals (arg);

9663    int parm_quals = cp_type_quals (parm);

9664

9665    if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM

9666        && !(strict & UNIFY_ALLOW_OUTER_MORE_CV_QUAL))

9667    {

9668      /* Although a CVR qualifier is ignored when being applied to a

9669        substituted template parameter ([8.3.2]/1 for example), that

9670        does not apply during deduction [14.8.2.4]/1, (even though

9671        that is not explicitly mentioned, [14.8.2.4]/9 indicates

9672        this). Except when we're allowing additional CV qualifiers

9673        at the outer level [14.8.2.1]/3,1st bullet.  */

9674      if ((TREE_CODE (arg) == REFERENCE_TYPE

9675           || TREE_CODE (arg) == FUNCTION_TYPE

9676           || TREE_CODE (arg) == METHOD_TYPE)

9677         && (parm_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)))

9678        return 0;

9679

9680      if ((!POINTER_TYPE_P (arg) && TREE_CODE (arg) != TEMPLATE_TYPE_PARM)

9681         && (parm_quals & TYPE_QUAL_RESTRICT))

9682        return 0;

9683    }

9684

9685    if (!(strict & (UNIFY_ALLOW_MORE_CV_QUAL | UNIFY_ALLOW_OUTER_MORE_CV_QUAL))

9686        && (arg_quals & parm_quals) != parm_quals)

9687      return 0;

9688

9689    if (!(strict & (UNIFY_ALLOW_LESS_CV_QUAL | UNIFY_ALLOW_OUTER_LESS_CV_QUAL))

9690        && (parm_quals & arg_quals) != arg_quals)

9691      return 0;

9692

9693    return 1;

9694 }

 

Fragment “typename T::t” refers to type ‘t’ defined within the context of ‘T’ (‘T’ is the template type parameter), and in the front-end, which has node TYPE_NAME_TYPE built for. And “T::template C” refers to template ‘C’ defined within the context of ‘T’ (‘T’ is the template type parameter), which has node UNBOUND_CLASS_TEMPLATE built with. And SCOPE_REF is the node built for reference to particular overloaded class method (for example, the template type parameter like: “void (T::*)()”).

Then according to [3], 14.8.2.4 [temp.deduct.type] , rule 4, template parameters used within nested-name-specifier (‘T::” in above expression) can’t be deduced.

 

unify (continue)

 

9780    if (!(strict & UNIFY_ALLOW_OUTER_LEVEL)

9781        && TYPE_P (parm) && !CP_TYPE_CONST_P (parm))

9782      strict &= ~UNIFY_ALLOW_MORE_CV_QUAL;

9783    strict &= ~UNIFY_ALLOW_OUTER_LEVEL;

9784    strict &= ~UNIFY_ALLOW_DERIVED;

9785    strict &= ~UNIFY_ALLOW_OUTER_MORE_CV_QUAL;

9786    strict &= ~UNIFY_ALLOW_OUTER_LESS_CV_QUAL;

9787    strict &= ~UNIFY_ALLOW_MAX_CORRECTION;

9788   

9789    switch (TREE_CODE (parm))

9790    {

9791      case TYPENAME_TYPE:

9792      case SCOPE_REF:

9793      case UNBOUND_CLASS_TEMPLATE:

9794        /* In a type which contains a nested-name-specifier, template

9795          argument values cannot be deduced for template parameters used

9796          within the nested-name-specifier.  */

9797        return 0;

9798

9799      case TEMPLATE_TYPE_PARM:

9800      case TEMPLATE_TEMPLATE_PARM:

9801      case BOUND_TEMPLATE_TEMPLATE_PARM:

9802        tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));

9803

9804        if (TEMPLATE_TYPE_LEVEL (parm)

9805               != template_decl_level (tparm))

9806          /* The PARM is not one we're trying to unify. Just check

9807              to see if it matches ARG. */

9808          return (TREE_CODE (arg) == TREE_CODE (parm)

9809                 && same_type_p (parm, arg)) ? 0 : 1;

9810        idx = TEMPLATE_TYPE_IDX (parm);

9811        targ = TREE_VEC_ELT (targs, idx);

9812        tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx));

9813

9814         /* Check for mixed types and values.  */

9815        if ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM

9816             && TREE_CODE (tparm) != TYPE_DECL)

9817           || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM

9818             && TREE_CODE (tparm) != TEMPLATE_DECL))

9819          return 1;

9820

9821        if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)

9822        {

9823          /* ARG must be constructed from a template class or a template

9824            template parameter.  */

9825          if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM

9826             && (TREE_CODE (arg) != RECORD_TYPE || !CLASSTYPE_TEMPLATE_INFO (arg)))

9827            return 1;

9828

9829          {

9830            tree parmtmpl = TYPE_TI_TEMPLATE (parm);

9831            tree parmvec = TYPE_TI_ARGS (parm);

9832            tree argvec = TYPE_TI_ARGS (arg);

9833            tree argtmplvec

9834               = DECL_INNERMOST_TEMPLATE_PARMS (TYPE_TI_TEMPLATE (arg));

9835            int i;

9836

9837            /* The parameter and argument roles have to be switched here

9838              in order to handle default arguments properly. For example,

9839              template<template <class> class TT> void f(TT<int>)

9840              should be able to accept vector<int> which comes from

9841              template <class T, class Allocator = allocator>

9842              class vector.  */

9843

9844            if (coerce_template_parms (argtmplvec, parmvec, parmtmpl, 0, 1)

9845                 == error_mark_node)

9846              return 1;

9847     

9848            /* Deduce arguments T, i from TT<T> or TT<i>. 

9849              We check each element of PARMVEC and ARGVEC individually

9850              rather than the whole TREE_VEC since they can have

9851              different number of elements.  */

9852

9853            for (i = 0; i < TREE_VEC_LENGTH (parmvec); ++i)

9854            {

9855              tree t = TREE_VEC_ELT (parmvec, i);

9856

9857              if (unify (tparms, targs, t,

9858                      TREE_VEC_ELT (argvec, i),

9859                      UNIFY_ALLOW_NONE))

9860                return 1;

9861            }

9862          }

9863          arg = TYPE_TI_TEMPLATE (arg);

9864

9865          /* Fall through to deduce template name.  */

9866        }

9867

9868        if (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM

9869           || TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)

9870        {

9871          /* Deduce template name TT from TT, TT<>, TT<T> and TT<i>.  */

9872

9873          /* Simple cases: Value already set, does match or doesn't.  */

9874          if (targ != NULL_TREE && template_args_equal (targ, arg))

9875            return 0;

9876          else if (targ)

9877             return 1;

9878        }

9879        else

9880        {

9881          /* If PARM is `const T' and ARG is only `int', we don't have

9882            a match unless we are allowing additional qualification.

9883            If ARG is `const int' and PARM is just `T' that's OK;

9884            that binds `const int' to `T'.  */

9885          if (!check_cv_quals_for_unify (strict_in | UNIFY_ALLOW_LESS_CV_QUAL,

9886                                    arg, parm))

9887             return 1;

9888

9889          /* Consider the case where ARG is `const volatile int' and

9890            PARM is `const T'. Then, T should be `volatile int'.  */

9891          arg = cp_build_qualified_type_real

9892                 (arg, cp_type_quals (arg) & ~cp_type_quals (parm), tf_none);

9893          if (arg == error_mark_node)

9894            return 1;

9895

9896          /* Simple cases: Value already set, does match or doesn't.  */

9897          if (targ != NULL_TREE && same_type_p (targ, arg))

9898            return 0;

9899          else if (targ)

9900            return 1;

9901

9902          /* Make sure that ARG is not a variable-sized array. (Note

9903            that were talking about variable-sized arrays (like

9904            `int[n]'), rather than arrays of unknown size (like

9905            `int[]').) We'll get very confused by such a type since

9906            the bound of the array will not be computable in an

9907            instantiation. Besides, such types are not allowed in

9908            ISO C++, so we can do as we please here.  */

9909          if (variably_modified_type_p (arg))

9910            return 1;

9911        }

9912

9913        TREE_VEC_ELT (targs, idx) = arg;

9914        return 0;

 

As we have seen, template parameter “class T” or “typename T” is represented by node of TEMPLATE_TYPE_PARM; and template template parameter like: “template <class T> class C”, is made with node TEMPLATE_TEMPLATE_PARM; when an argument (in form of template-id) is given for the template template paramter, BOUND_TEMPLATE_TEMPLATE_PARM node is generated (template template arguments).

Remember tparms is the vector for template parameters (comes from the top-most fn_type_unification by retrieving DECL_INNERMOST_TEMPLATE_PARMS of fn , and see tparms is unchanged even when recursing into unify ).

Considering comparison at line 9804, think following statements:

template <template <class [U]opt > class TT, class T> void func(T, TT <T>) {}

template <class T> class B {};

main () {

    func (int, B <int> ());      // func (float, B <int> ()) fails for unify

}

Notice that “<>” introduces a new nested binding scope, so first statement is the only form that can using template template argument as fucntion argument (and similar form as member of class template using template template argument); in this declaration of func , U is optional as it’s invisible outside of the enclosing ‘<>’. See in the TEMPLATE_TEMPLATE_PARM for TT, its inner parameter is the same as the outer one. So when deducing this inner parameter ‘T’ for TT (note func is a deduced context), tparm will have level 1 (as tparms always refers to the most-outer template parameters list), and when parm referring ‘T’ in ‘TT’, it will have level 2. At that point, parm should have been deduced successfully, because ‘T’ appears before TT in func (and vice versa if exchange T with TT in func ). No doubt, for the case, parm and arg (i.e., deduced parm beforehead) must be the same type.

Furth er, if replacing above U with another template declaration, for example:

template <template < template <class [U]opt > class [V]opt > class TTT,

template <class [W]opt > class TT, class T> void func (TTT<TT>, T) {}

template <template <class T> class A> class Obj {};

template <class T> class B {};

main () {

    func(1, Obj<B> ()); // can change B to antoher template of the same form

}

And consider another example:

template < template <class > class TTT, template <class > class TT,

          class T > void func(T, TT<T>, TTT<TT<T> >) {}

template <class T> class B {};

main () {

    func(1, B<int>(), B<B<int> >());   // the three parameters must match each other

}

Above code can handle both cases correctly due to the trait that ‘<>’ introduces new enclosing binding scope. And that is why it always uses tparms as the template parameter of the outmost template (in readonly way).

Then if parm is BOUND_TEMPLATE_TEMPLATE_PARM, TYPE_TI_TEMPLATE (parm ) is the TEMPLATE_DECL instantiated or specialized by parm , this TEMPLATE_DECL will be the immediate parent, not the most general template. For example, in:

template <class T> struct S { template <class U> class F {}; };

The RECORD_TYPE for S<int>::F<double> will have, as its TYPE_TI_TEMPLATE, “template <class U> S<int>::F<U>”.

Then TYPE_TI_ARGS (parm ) are the template arguments used to obtain this declaration (i.e, parm ) from the most general form of the TEMPLATE_DECL (parm ) in TYPE_TI_TEMPLATE. For the TYPE_TI_TEMPLATE of above example, the TYPE_TI_ARGS will be {int, double}. These are always the full set of arguments required to instantiate this declaration from the most general template specialized here.

Note the condition at line 9825, we rewrite it as below:

  (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM ||

  ! (TREE_CODE (arg) == RECORD_TYPE && CLASSTYPE_TEMPLATE_INFO (arg)))

So arg is either BOUND_TEMPLATE_TEMPLATE_PARM, or instantiation of class template. And similarly TYPE_TI_ARGS (arg ) also hold the template arguments used to obtain arg from the most general form of TYPE_TI_TEMPLATE (arg ).

Then the invocation of coerce_template_parms at line 9844 converts all template arguments to their appropriate types, and return a vector containing the innermost resulting template arguments. For the function, argument parms is passed with argtmplvec - the template parameters in TYPE_TI_TEMPLATE (arg ), and argument args is passed with parmvec – the template arguments by TYPE_TI_ARGS (parm ). Comment at line 9837 explains the reason is for acceptting default arguments.

If argtmplvec can be converted to parmvec , it goes on to check if can deduce parmvec from argvec . (Note, argtmplvec is the full set of template arguments to instantiate this template, and argvec is the set of arguments used to verify the deduced parameters).

If targ is not NULL for template template argument, it means we have already deduced the template template parameter, it must be the same template declaration as arg given here. Next, code from line 9879 to 9914, shows how to deduce template parameter ‘T’. It is the one of final places we will arrive for deducing parameter.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值