演绎的过程:
描述实参-参数对匹配情况:
匹配类型A(来自实参的类型),参数化类型P(来自参数的声明)
如果实参的是数组或函数类型,那么会发生decay转型,转化为对应的指针类型,同时还会忽略高层次的const和volatile限定符。
template <typename T> void f(T); //P就是T
template <typename T> void g(T&); //P仍然是T
double x[20];
int const seven = 7;
f(x); //T是double*
g(x); //T是double[20]
f(seven); //T是int
g(seven); //T是int const
f(7); //T是int
g(7); //错误,不能把传递给int&
演绎的上下文:
template <typename T1, typename T2, typename T3>
void f(T1 (T2::*) (T3*) );
class S {
public:
void f(double*);
};
void g(int*** ppp) {
f(&S::f);
}
演绎T1=void,T2=S,T3=double。
解释:
f的参数是一个函数,函数的返回值是T1,函数的依赖关系由T2::*体现,函数的参数是T3*。
例:
template <int N>
class X {
public:
typedef int I;
void f(int) {
}
};
template<int N>
void fppm(void (X<N>::*p)(typename X<N>::I));
int main()
{
fppm(&X<33>::f); // 正确,N被演绎成33
}
子构造X<N>::I是一个不可演绎的上下文,然而,具有成员指针类型的成员类型部分X<N>是一个可以演绎的上下文。
特殊的演绎情况:
1.取函数模板的地址
template <typename T>
void f(T, T);
void (*pf) (char, char) = &f;
2.与转型运算符模板一起出现
class S {
public:
template<typename T, int N> operator T[N]&();
};
void f(int (&)[20]);
void g(S s) {
f(s); //能成功演绎
}
可接受的实参转型:
1.如果原来声明的参数是一个引用参数子,那么被替换的P类型可以比A类型多一个const或volatile限定符
2.如果A类型是指针类型或者成员指针类型,那么它可以进行限定符转型,转化为被替换的P类型
3.当演绎过程不涉及到转型运算符模板的时候,被替换的P类型可以是A类型的基类,或者当A是指针类型时,P可以是一个指针类型,它所指向的类型是A所指向的类型的基类。
类模板参数:
模板实参演绎只能应用于函数模板和成员函数模板,是不能应用于类模板的。对于类模板的构造函数,也不能根据实参来演绎类模板参数。
缺省调用实参:
对于缺省调用实参而言,即使不是依赖型的,也不能用于演绎模板实参:
template <typename T>
void f(T x = 42) { }
int main() {
f<int> (); //正确
f(); //错误,不能根据缺省调用实参来演绎T
}
C++ Templates:模板实参演绎
最新推荐文章于 2024-09-19 13:36:34 发布