[C++ Template]深入模板--模板实参演绎

目录

第11章 模板实参演绎

11.1 演绎的过程

11.2 演绎的上下文

11.3 特殊的演绎情况(比较晦涩,不理解)

11.4 可接受的实参转型

11.5 类模板参数

11.6 缺省调用实参


第11章 模板实参演绎

在每个函数模板的调用中, 如果都显式地指定模板实参(例如,concat<std::string, int>(s,3) ) , 那么很快就会导致很繁琐的代码。 幸运的是, 借助于功能强大的模板实参演绎过程, C++编译器通常都可以自动地确定这些所需要的模板实参(即隐式实例化)。

 

11.1 演绎的过程

针对一个函数调用, 演绎过程会比较“调用实参的类型”和“函数模板对应的参数化类型(即T) ”, 然后针对要被演绎的一个或多个参数,分别推导出正确的替换。 我们应该记住: 每个实参-参数对的分析都是独立的; 因此, 如果最后所得出的结论发生矛盾, 那么演绎过程将失败。考虑下面的例子:

template<typename T>
T const& max(T const& a, T const& b)
{
	return a < b ? b : a;
}
int g = max(1, 1.0);

即使所有被演绎的模板参数都可以一致性地确定(即不发生矛盾) , 演绎过程也可能会失败。 这种情况就是: 在函数声明中, 进行替换的模板实参可能会导致无效的构造。 请看下面的例子:

template<typename T>
typename T::ElementT at(T const& a, int i)
{
	return a[i];
} 
void f(int* p)
{
	int x = at(p, 7);
}

在此, T被演绎成int*(只有一个参数类型与T有关, 当然也就不会发生前面的分析矛盾) 。 然而, 在返回类型T::ElementT中, 用int*来替换T之后, 显然会导致一个无效的C++构造, 从而也使这个演绎过程失败。

我们接下来需要描述实参-参数对是如何进行匹配的。 我们会使用下面的概念来进行描述: 匹配类型A(来自实参的类型) 和参数化类型P(来自参数的声明) 。 如果被声明的参数是一个引用声明(即T&) ,那么P就是所引用的类型(即T) , 而A仍然是实参的类型。 否则的话,P就是所声明的参数类型, 而A则是实参的类型; 如果这个实参的类型是数组或者函数类型, 那么还会发生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); //非引用参数(针对f): T是double*
g(x); //引用参数(针对g): T是double[20]
f(seven); //非引用参数: T是int.
g(seven); //引用参数: T是int const
f(7); //非引用参数: T是int
g(7); //引用参数: T是int =>错误: 不能把7传递给int&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值