然后如果一切顺利,最后通过 10401 的 fn_type_unifcation 把推导后实参放入 targs 。而这些实参接着在 resolve_overloaded_unification 的 9334 行,立即由 tsubst 替代入模板形参。
接着在下面的函数中, tparms 指向模板形参; orig_targs 是推导出的实参的 vector ;两者都是调用者 resolve_overloaded_unification 的参数 tparms 及 targs ,并且在下面的过程中都不会改变。而 targs 是 orig_tags 的拷贝; parm 是模板形参; arg 则是相应的模板实参(在这里它们是函数指针类型);而 addr_p 如果是 true ,表示看到“ & ”。
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);
当使用指向函数指针( pointer-to-function )或指向方法指针( pointer-to-method )的模板形参时,我们可以仅使用“ &A::f ”或“ &f ”(对于函数,还可以使用“ f ”)及 typedef 别名作为实参,因为前端要求编译时的常量。因此上面,在看到这样的结构后,构建相应的指针。
【 3 】的 [temp.deduct.conv] 定义到“模板实参推导,通过模板转换函数的返回类型 (称之为 P )与作为转换结果所要求的类型(称之为 A )的比较,如 14.8.2 .4 所示,来完成。 ”
而 [temp.deduct.call] 提到:“模板实参推导,通过所下所示的,比较每个函数模板形参类型 (称之为 P )与调用的对应实参类型(称之为 A ),来完成 ”。
记住对于转换操作符,已经把该操作符的返回类型加入到了形参列表,被期望的类型加入到了实参列表。并且看到在该操作符的调用点,它将尝试把返回类型转换为被期望的类型(即从形参到实参,而不是像函数参数那样从实参到形参)。因此下面的函数首先通过 DEDUCE_CONV 交换了这两者(现在,对于转换操作符的规则, P 变成了 A , A 变成了 P )。进一步的,【 3 】有如下定义:
来自 [temp.deduct.call] 2. 如果 P 不是一个引用类型: — 如果 A 是一个数组类型,由数组到指针标准转换( 4.2 )产生的指针类型,在类型推导中,取代 A ;否则, — 如果 A 是一个函数类型,由函数到指针标准转换( 4.3 )产生的指针类型,在类型推导中,取代 A ;否则, — 如果 A 是一个 cv- 限定的类型,对于类型推导, A 的类型的顶层 cv- 限定词被忽略。 如果 P 是一个 cv- 限定的类型,对于类型推导, P 的类型的顶层 cv- 限定词被忽略。如果 P 是一个引用类型,在类型推导中,为 P 所引用的类型被使用。 来自 [temp.deduct.conv] 2. 如果 A 不是一个引用类型: — 如果 P 是一个数组类型,由数组到指针标准转换( 4.2 )产生的指针类型,在类型推导中,取代 P ;否则, — 如果 P 是一个函数类型,由函数到指针标准转换( 4.3 )产生的指针类型,在类型推导中,取代 P ;否则, — 如果 P 是一个 cv- 限定的类型,对于类型推导, P 的类型的顶层 cv- 限定词被忽略。 如果 A 是一个 cv- 限定的类型,对于类型推导, A 的类型的顶层 cv- 限定词被忽略。如果 A 是一个引用类型,在类型推导中,为 A 所引用的类型被使用。 来自 [temp.deduct.call] 3. 通常,推导处理尝试找出将使得推导后的 A 与 A (在如上所述的转换后的类型 A )相同的模板实参值。不过,有三种情况允许不同: — 如果初始的 P 是一个引用类型,推导的 A (即,由该引用引用的类型)可以是比 A 更严格的 cv- 限定。 — A 可以是另一个指针或指向成员指针类型,它可以通过一个限定转换( 4.4 )转换到推导的 A 。 — 如果 P 是一个类,并且 P 具有 template-id 的形式,那么 A 可以是推导的 A 的一个派生类。同样,如果 P 是一个具有 template-id 形式的类的指针, A 可以是推导的 A 所指向类的一个派生类的指针。 仅当类型推导没有其它选择,才考虑这些替代方案。如果它们产生多于一个可能的推导的 A ,类型推导失败。 [ 注意:如果一个模板形参在一个函数模板的任一一个函数形参中都没有使用,或者仅用在一个非推导( non-deduced )的上下文,其对应的模板实参不能从一个函数调用中推导,这个模板实参必须被显式指定 ] 。 来自 [temp.deduct.conv] 3. 通常,推导处理尝试找出将使得推导后的 A 与 A 相同的模板实参值。不过,有两种情况允许不同: — 如果初始的 A 是一个引用类型, A 可以是比推导的 A (即,由该引用引用的类型)更严格的 cv- 限定。 — 推导的 A 可以是另一个指针或指向成员指针类型,它可以通过一个限定转换转换到 A 。 仅当类型推导没有其它选择,才考虑这些替代方案。如果它们产生多于一个可能的推导的 A ,类型推导失败。 |
看到通过交换 arg 与 parm ,可以把 [temp.deduct.call] 的第二个规则同时用于函数调用及转换操作符,而不需作出改变。而对于 [temp.deduct.call] 及 [temp.deduct.conv] 的第三个规则,观察下面的例子:
例 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
类 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
}
如果恢复上面注掉的语句,将导致 cv- 限定冲突的错误。可以看到对于转换操作符,通过交换 parm 及 arg ,我们可以安全地为函数调用及转换操作符,统一使用推导函数调用的规则 3 中的前两个替代方案。而对于函数调用规则 3 中的第三个替代方案,前端可以通过不设定标记 UNIFY_ALLOW_DERIVED ,来为转换操作符避免它。
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 }
那么函数 maybe_adjust_types_for_deduction 根据上面表中由【 3 】指定规则转换实参。 9035 行的注释提及了【 3 】中的一个瑕疵,并给出了 EDG (最好的 C++ 前端)所采纳的一个可能的解决方案。
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;
【 3 】的条文 14.8.2 .4 “从一个类型推导模板实参”如下所示 [temp.deduct.type ] :
1. 模板实参可以在几个不同的上下文中推导,但在每个情形中,以模板形参指定的一个类型(称之为 P )被与一个实际上的类型(称之为 A )比较,并且尝试找出模板实参值(对于一个类型参数是一个类型,对于非类型参数是一个值,或者对于模板参数是一个模板),它将使得 P ,在进行推导值的替换后(称之为推导的 A ),与 A 相容。 2. 在某些情况下,推导使用单组类型 P 及 A 完成。在其他情况下,将有一组对应的类型 P 及 A 。对于每对 P/A ,类型推导独立完成,然后推导的模板实参值被组合起来。如果对任一 P/A 对,类型推导不能完成;或者如果对于任一对,导致推导出多于一组可能的推导值;或者如果不同的对产生不同的推导值;或者如果任一模板实参保持未推导,及未被显式指定;模板实参推导失败。 3. 一个给定的类型 P 可以由一定数目的其他类型,模板,及非类型值组成: — 一个函数类型包括每个函数参数的类型及返回类型。 — 一个指向成员类型的指针包括所指向类对象的类型,及所指向成员的类型。 — 一个类模板特化(如, A<int> )的一个类型包括该特化实参列表所引用的类型,模板,及非类型值。 — 一个数组类型包括数组元素的类型,及数组边界值。 在大多数情况下,构成 P 的类型,模板,非类型值参予模板实参推导。也就是说,它们可能被用于确定一个模板实参的值,并且这里确定的值必须与其他地方确定的值一致。然而,在某些上下文中,该值不参予类型推导,而是使用在其他地方推导的,或者显式指定的模板实参的值。如果一个模板实参仅用在非推导上下文,并且没有被显式指定,模板实参推导失败。 4. 非推导上下文是: — 使用一个 qualified-id 所指定的一个 nested-name-specifier 形式的 type 。 —一个 template-id 形式的类型,其中一个或多个模板实参是一个引用模板形参的表达式。 当一个类型的名字在以一个包含非推导上下文的方式指定时,所有组成这个类型名的类型也都是非推导的。不过,一个复合类型( compound type )可以同时包括推导及非推导类型。 [ 例如:如果一个类型被指定为 A<T>::B<T2> , T 及 T2 两者都是非推导的。类似的,如果一个类型被指定为 A<I+J>::X<T> , I , J ,及 T 都是非推导的。如果一个类型被指定为 void f(typename A<T>::B, A<T>) ,在 A<T>::B 中的 T 是非推导的,但在 A<T> 中的 T 是推导的 ] 。 5. [ 例如:这里有一个例子,在其中不同的形参 / 实参对产生不一致的模板实参推导: 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. 这里有一个例子,其中的 2 个模板实参从单个函数形参 / 实参对推导出来。这会导致冲突使得类型推导失败: 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. 这里有一个例子,其中在函数调用的实参类型与推导的模板实参类型之间,应用了一个限定转换: template <class T> void f(const T*) {} int *p; void s() { f(p); // f(const int *) } 8. 这里有一个例子,其中的模板实参用于具现对应函数形参类型的一个派生类: 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>&) } —例子结束 ] 9. 一个模板类型实参 T ,一个模板模板实参 TT ,或一个模板非类型实参 i 可以被推导,如果 P 及 A 具有如下的形式: T cv-list T T* T& T[integer-constant] template-name<T> (其中 template-name 引用一个类模板) 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> (其中 template-name 引用一个类模板) TT<T> TT<i> TT<> 其中 (T) 代表至少一个实参类型包含一个 T 的实参列表;而 () 代表没有参数包含一个 T 的实参列表。同样, <T> 代表至少一个实参包含一个 T 的模板实参列表, <i> 代表至少一个实参包含一个 i 的模板实参列表,而 <> 代表没有实参包含一个 T 或 i 的模板实参列表。 10. 这些形式可以以相同的方式来使用,因为 T 可用于进一步的类型合成。 [ 例如: X<int> (*)(char[6]) 具有形式 template-name<T> (*)(type[i]) 它是下面的一个变形 type (*)(T) 其中 type 是 X<int> , 而 T 是 char[6] 。 ] 11. 模板实参不能从涉及上述以外结构的函数实参中推导。 12. 一个模板类型实参不能根据一个非类型模板实参的类型来推导。 [ 例如: 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 —例子结束 ] 13. [ 注意:除了作为引用及指针类型,一个主要数组边界不能是一个函数形参类型的一部分,并且不能从一个实参推导出来: 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. 如果,在一个带有一个非类型模板参数的函数模板的声明中,该非类型模板形参被用于该函数形参列表中的一个表达式里,对应的模板实参必须总是显式指定或从其他地方推导出来;不然的话,对于这样的一个模板实参,类型推导将失败。 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 } — 注意结束 ] [ 注意:如果仅用在非推导上下文中,模板形参不参予模板实参的推导。例如, 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 — 注意结束 ] 15. 如果,在一个带有一个非类型模板参数的函数模板的声明中,该非类型模板形参被用于该函数形参列表中的一个表达式里,并且如果对应的模板实参被推导,该模板实参的类型必须与该模板形参的类型严格匹配(虽然对应一个类型为 bool 的模板形参的模板实参可以从一个数组边界推导,其结果将总是 true ,因为数组边界不会为 0 )。 [ 例如:除了一个从数组边界推导的模板实参可能具有任意整数类型。 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 } —例子结束 ] 16. 一个模板实参可以从一个函数指针或成员函数指针形式的实参推导,只要该重载函数组不包含函数模板,并且对重载函数组的匹配中不出现二义性。 [ 例如: 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 } —例子结束 ] 17. 一个模板类型形参不能从一个函数缺省实参的类型中推导。 [ 例如: 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) } —例子结束 ] 18. 对应一个模板模板形参的模板实参,从在一个函数调用的实参列表中的,一个类模板特化的模板实参类型来推导。 [ 例如: 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>) —例子结束 ] [ 注意:一个缺省的模板实参不能在一个函数模板声明或定义中指定;因而缺省模板实参不能用于改变模板实参推导 ] 。 |
函数 unify 执行真正的推导,如果成功返回 0 。其中,参数 tparms 是所处理模板的模板形参(这里它是只读的); targs 是保存了推导的实参的 vector (看到它是上面新产生的空 vector tempargs 。因为 unify 的每次调用只推导一对形参 / 实参,而 try_one_overload 本身也只通过 unify 推导函数指针对,这样必然涉及 unify 的递归调用;因此这个函数需要把当前推导结果合并入 targs ); arg 是要被推导的实参;而 parm 是对应的形参。
参数 strict 是下面标记的按位与的组合:
UNIFY_ALLOW_NONE :要求 PARM 与 ARG 是严格匹配。
UNIFY_ALLOW_MORE_CV_QUAL :允许推导的 ARG 比 ARG 具有更多的 cv- 限定(通过限定转换)。
UNIFY_ALLOW_LESS_CV_QUAL :允许推导的 ARG 比 ARG 具有更弱的 cv- 限定。
UNIFY_ALLOW_DERIVED :允许推导的 ARG 是 ARG 的一个模板基类类型,或者是指向由 ARG 指向的类的一个模板基类类型的指针。
UNIFY_ALLOW_INTEGER :允许推导出任一整数类型。更多信息,参见 TEMPLATE_PARM_INDEX 的说明。
UNIFY_ALLOW_OUTER_LEVEL :这是最外层的一个推导。用于确定限定转换的有效性。一个有效的限定转换必须具有 const 限定的,能达成要求额外 cv 限定的内层类型的指针,除了在最外层,那里 const 不被要求 [conv.qual] 。这个标记通常与标记 UNIFY_ALLOW_MORE_CV_QUAL 一同设置。
UNIFY_ALLOW_OUTER_MORE_CV_QUAL :这是最外层的一个推导,并且在这一点上 PARM 可以有更多 cv- 限定。
UNIFY_ALLOW_OUTER_LESS_CV_QUAL :这是最外层的一个推导,并且在这一点上 PARM 可以是更弱的 cv- 限定。
UNIFY_ALLOW_MAX_CORRECTION :这是一个 INTEGER_TYPE 的最大值。用在如果取值范围从一个大小规格,比如一个数组大小,导出。如果该大小由一个非类型模板形参 N 给定,其最大值将具有形式 N-1 。这个标记说明我们可以(实际上是必须)使 N 与( ARG + 1 )统一,是折叠 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;
9764 到 9778 行,如注释所言,因为不匹配的 cv- 限定拒绝某些对。看到这里我们需要保守些,仅考虑具有相同编码的模板形参及实参。这里滤除了 ARRAY_TYPE 及 TEMPLATE_TYPE_PARM (代表形如“ T ”的模板类型形参),因为它们在后面将得到特殊的处理。
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 }
片段“ typename T::t ”指向定义在‘ T ’(‘ T ’是模板类型形参)上下文中的类型‘ t ’,在前端中为它构建了 TYPE_NAME_TYPE 节点。而“ T::template C ”指定义在‘ T ’(‘ T ’是模板类型形参)上下文中的模板‘ C ’, 在前端中构建了 UNBOUND_CLASS_TEMPLATE 节点。而 SCOPE_REF 是为特定重载的类方法的引用所构建的节点(例如,形如:“ void (T::*)() ”的模板类型形参)。
那么根据【 3 】, 14.8.2 .4 [temp.deduct.type] ,规则 4 :用在 nested-name-specifier 中(在上面表达式中的‘ T:: ’)的模板参数不能被推导。
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;
我们已经看到,模板参数“ class T ”或“ typename T ”,由节点 TEMPLATE_TYPE_PARM 来表示;而形如:“ template <class T> class C ”的模板模板参数,则被构建为节点 TEMPLATE_TEMPLATE_PARM ;当对该模板模板参数给定一个实参(以 template-id 的形式),就产生 BOUND_TEMPLATE_TEMPLATE_PARM 节点(模板模板实参)。
记得 tparms 是模板形参的 vector (来自最上层的 fn_type_unification ,通过提取 fn 的 DECL_INNERMOST_TEMPLATE_PARMS 得到,并且看到,即便递归入 unify , tparms 也不改变)。
考虑 9804 行的比较,思考下面的语句:
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
}
注意到“ <> ”引入了一个新的绑定域,因此第一个语句是仅有的,能使用模板模板实参作为函数实参的形式(类似的形式,作为使用模板模板实参类模板成员);在这个 func 的声明中, U 是可选的,因为它在封闭它的‘ <> ’之外是不可见的。在为 TT 构建的 TEMPLATE_TEMPLATE_PARM 中,其内层参数与外层参数相同。因此当为 TT 推导这个内层参数‘ T ’的实参时(注意, func 不是非 推导上下文), tparm 将具有层次 1 (因为 tparms 总是指向最外层的模板形参列表),并且当 parm 指向‘ TT ’中的‘ T ’时,它将具有层次 2 。在那一点上, parm 应该已经被成功推导,因为在 func 中‘ T ‘出现在‘ TT ’之前(反之亦然,如果在 func 中交换 T 和 TT 的次序)。毫无疑问,对于这个情形, parm 及 arg (即,之前推导的 parm )必然是相同的类型。
进一步的,如果用其他模板声明来替换上面的 U ,例如:
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
}
并且考虑另一个例子:
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
}
上面的代码能够正确处理这两个例子,这归功于‘ <> ’引入新的封闭的绑定域。这也是为什么把 tparms 用作最外层模板的模板参数(以只读的方式)。
而如果 parm 是 BOUND_TEMPLATE_TEMPLATE_PARM , TYPE_TI_TEMPLATE (parm ) 则是由 parm 具现或特化的 TEMPLATE_DECL ,这个 TEMPLATE_DECL 将是直接父亲,但不是最泛化形式的模板。例如,在:
template <class T> struct S { template <class U> class F {}; };
“ S<int>::F<double> ”的 RECORD_TYPE 将具有,作为其 TYPE_TI_TEMPLATE ,“ template <class U> S<int>::F<U> ”。
那么 TYPE_TI_ARGS (parm ) 就是,从保存在 TYPE_TI_TEMPLATE (parm ) 中的 TEMPLATE_DECL 的最泛化形式,得到这个声明(即 parm )的模板实参。对于上例的 TYPE_TI_TEMPLATE ,对应的 TYPE_TI_ARGS 将是 {int, double} 。它们总是从这里指定的最泛化形式的模板来具现这个声明,所需要的一组完整的实参。
注意在 9825 行的条件,我们把它改写为如下:
(TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM ||
! (TREE_CODE (arg) == RECORD_TYPE && CLASSTYPE_TEMPLATE_INFO (arg)))
因此 arg 要么是 BOUND_TEMPLATE_TEMPLATE_PARM ,要么是类模板的具现。类似的, TYPE_TI_ARGS (arg ) 也保存了从 TYPE_TI_TEMPLATE (arg ) 的最泛化形式,得到 arg 的模板实参。
那么在 9844 行的对 coerce_template_parms 调用中,把所有模板实参转换到合适的类型,并返回一个包含最内层模板实参结果的 vector 。对这个函数中,向参数 parms 传递了 argtmplvec - TYPE_TI_TEMPLATE (arg ) 的模板形参,向参数 args 传递了 parmvec – 来自 TYPE_TI_ARGS (parm ) 的目标实参。 9837 行的注释解释这样的原因在于接受缺省实参。
如果 argtmplvec 可以转换到 parmvec ,那么就可以检查是否可以从 argvec 推导出 parmvec (注意, argtmplvec 是具现这个模板的一组完整的模板实参,而 argvec 则是需要验证形参推导的实参集)。
如果对于模板模板实参 targ 不是 NULL ,这意味着我们已经推导了这个模板模板形参,它必须与这里给定的 arg 具有相同的模板声明。接着,从 9879 到 9914 行的代码,显示了如何推导模板形参‘ T ’。对于形参推导,这是我们最后到达的地方。
unify (continue)
9916 case TEMPLATE_PARM_INDEX:
9917 tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
9918
9919 if (TEMPLATE_PARM_LEVEL (parm)
9920 != template_decl_level (tparm))
9921 /* The PARM is not one we're trying to unify. Just check
9922 to see if it matches ARG. */
9923 return !(TREE_CODE (arg) == TREE_CODE (parm)
9924 && cp_tree_equal (parm, arg));
9925
9926 idx = TEMPLATE_PARM_IDX (parm);
9927 targ = TREE_VEC_ELT (targs, idx);
9928
9929 if (targ)
9930 return !cp_tree_equal (targ, arg);
9931
9932 /* [temp.deduct.type] If, in the declaration of a function template
9933 with a non-type template-parameter, the non-type
9934 template-parameter is used in an expression in the function
9935 parameter-list and, if the corresponding template-argument is
9936 deduced, the template-argument type shall match the type of the
9937 template-parameter exactly, except that a template-argument
9938 deduced from an array bound may be of any integral type.
9939 The non-type parameter might use already deduced type parameters. */
9940 tparm = tsubst (TREE_TYPE (parm), targs, 0, NULL_TREE);
9941 if (!TREE_TYPE (arg))
9942 /* Template-parameter dependent expression. Just accept it for now.
9943 It will later be processed in convert_template_argument. */
9944 ;
9945 else if (same_type_p (TREE_TYPE (arg), tparm))
9946 /* OK */ ;
9947 else if ((strict & UNIFY_ALLOW_INTEGER)
9948 && (TREE_CODE (tparm) == INTEGER_TYPE
9949 || TREE_CODE (tparm) == BOOLEAN_TYPE))
9950 /* Convert the ARG to the type of PARM; the deduced non-type
9951 template argument must exactly match the types of the
9952 corresponding parameter. */
9953 arg = fold (build_nop (TREE_TYPE (parm), arg));
9954 else if (uses_template_parms (tparm))
9955 /* We haven't deduced the type of this parameter yet. Try again
9956 later. */
9957 return 0;
9958 else
9959 return 1;
9960
9961 TREE_VEC_ELT (targs, idx) = arg;
9962 return 0;
在上面的 9812 行,如果 tparm 指向 TEMPLATE_PARM_INDEX ,我们在解释解析器行为的例子中已经看过(参考 第二个例子 一节)。域 TEMPLATE_PARM_IDX (简称为 IDX )给出了该形参的索引(从 0 开始),而域 TEMPLATE_PARM_LEVEL (简称为 LEVEL )给出该形参的层次(从 1 开始)。例如:
template <class T> // Index 0, Level 1
struct S {
template <class U, // Index 0, Level 2
class V> // Index 1, Level 2
void f();
};
该例子产生 3 个 TEMPLATE_PARM_INDEX 。在这些节点中,一个由作为它们后裔的 TEMPLATE_PARM_INDEX 节点组成的链表,保存在 TEMPLATE_PARM_DESCENDANTS 域。第一个后裔将具有相同的 IDX ,但其 LEVEL 将少 1 。 TREE_CHAIN 域用于串接这些后裔。在后裔中,域 TEMPLATE_PARM_DECL 是该形参的声明,它要么是一个 TYPE_DECL ,要么是一个 CONST_DECL 。域 TEMPLATE_PARM_ORIG_LEVEL (简称为 ORIG_LEVEL )是最远父亲的 LEVEL ,即,该形参在被声明时所具有的初始 LEVEL 。例如,如果我们具现 S<int> ,我们将有:
struct S<int> {
template <class U, // Index 0, Level 1, Orig Level 2
class V> // Index 1, Level 1, Orig Level 2
void f();
};
其 LEVEL 是,我们现在所关心的形参的层次;其 ORIG_LEVEL 是,当我们关心模板具现的细节时的层次。
注意到 targs 将是保存推导实参的 vector ,如果相应的项不为空,就表示该实参之前已经被推导了(或显式指定)。显然,这个已推导的实参必须与这里要推导的实参相同(这意味着同一个形参的两次不同的推导)。看到在 unify 及其递归中, targs 都不变化。那么在 9940 行,把它替换入由 parm 指定的模板,由 tparm 指向由此推导出的实参。对于成功有效的推导,毫无疑问, tparm 必须与 arg 的类型相同(除了使用 UNIFY_ALLOW_INTEGER 的情形)。
注意 9941 行,如果 TREE_TYPE 是 NULL , arg 应该是一个形如‘ T ’的 IDENTIFIER_NODE 。而如果在 9940 行所推导的 tparm 仍然依赖于模板形参,这些未推导的形参,在回到 try_one_overload 后将可能再被解析,或被发现是错误。现在可以安全地接受它。