在大多数情况下,当使用模板的名称时,编译器需要确定模板参数是什么,这决定了它所表示的模板的确切专门化。
听起来您很熟悉如何对类模板执行此操作(为了简单起见,忽略模板参数包):
-
中的每个参数
<>
是模板参数之一,从一开始就按顺序排列。
-
如果模板的模板参数多于
<>
,其余位置使用默认模板参数(这些默认模板参数必须存在)。
但是对于函数模板,还有第三种可能,自动推导模板参数。您可能熟悉这样一种想法,即从对函数模板的调用中推断模板参数
func(a1, a2)
. 但是演绎也可以是这样的形式
func<x1, x2>(a1, a2)
,并可以与模板参数的其他源混合和匹配(再次忽略模板参数包):
-
中的每个参数
<>
是模板参数之一,从一开始就按顺序排列。在进入下一步之前,这些参数将替换函数类型中所有对应的模板参数。
-
任何剩余的模板参数都可以推导出来(从调用中的参数表达式类型,或者从在这种情况下匹配声明时声明的参数类型
friend
用法)。
-
对于任何未显式指定且未推导的剩余模板参数,可以使用默认模板参数。(C++ 11和后来的只有-C++ 03不允许函数模板有默认模板参数。)
所以在函数调用的情况下,使用
func<>(a1, a2)
,这意味着所有模板参数都将从
a1
和
a2
或者从默认模板参数中获取。这基本上和
功能(A1,A2)
,除了
功能(A1,A2)
,重载解析可能会选择一个非模板函数,该函数也被命名为
func
;但使用
功能<gt;(A1,A2)
,只有模板才有资格考虑。
类似地,friend声明中可能需要模板参数列表,以确保编译器知道它命名的是函数模板的专门化,而不是普通的非模板函数。再说一次,通常是空名单
<>
假设所有模板参数都可以从函数参数类型中推导出来,就可以了。注意这里的区别:
template <class T> class A;
template <class X> void f1(A<X>);
template <class X> void f2(A<X>);
template <class X> void f3(A<X>);
template <class X> void f4(A<X>);
template <class T>
class A {
// For each class type A<T>, declares just the one specialization f1<T>
// to be a friend. So f1<int>(A<int>) is a friend of A<int>, but is not
// a friend of A<double>.
friend void f1<T>(A<T>);
// Exactly the same (but for f2<T>).
// A is the "injected class name" typedef for A<T>.
// The argument for f2's X is deduced to be X=T.
friend void f2<>(A);
// Declares ALL specializations of f3 to be friends of all specializations of A.
template <class U>
friend void f3(A<U>);
// Declares a non-template function. Each class type A<T> declares
// a different function unrelated to the template f4 above or to
// the f4 declared by other A<U> types. You could define the
// individual overloaded functions void f4(A<int>), void f4(A<double>),
// etc., but only one at a time, and only if you know all the
// possible types to be used!
friend void f4(A);
};
是不是更普遍的情况是:
template<class T1, class T2, ...>
class A{
double p_;
friend double f<>(A const& a); // same as double f<T1, T2, ...>?
};
?
可能吧。尽管这不仅仅是直接从正在实例化的封闭类模板专门化中获取模板参数的问题。模板参数推导可以得到更丰富的内容。例如,如果我们有
template <class T1, class T2> class A;
template <class X>
double f(A<X, X> const& a); // #1
template <class X>
double f(A<X, X*> const& a); // #2
template <class X, class Y>
double f(A<X, Y> const& a); // #3
template <class T1, class T2>
class A {
friend double f<>(A const&);
};
那么对于不同的
A
!功能
double f<int>(A<int, int> const&)
来自模板1是
A<int, int>
,函数
double f<int>(A<int, int*> const&)
模板2是
A<int, int*>
,以及函数
double f<int*, int>(A<int*, int> const&)
模板3是
A<int*, int>
. 没有其他模板专门化是这三个专门化的朋友
一
.