C++模板编程
1.函数模板
1.1示例函数模板
template <typename T>
const T& Max(const T& tA, const T& tB)
{
return tA > tB ? tA : tB;
}
函数模板代表了一个函数家族
1.2关键字说明
typename:关键字 typename 引入了参数类型T,老版本的C++使用的是 class
1.3模板的调用
Max(10, 20);
使用了 int 类型作为模板的参数T的函数模板,实例化如下的函数
const int& Max(const int& nA, const int& nB)
{
return nA > nB ? nA : nB;
}
1.4实例化
- 具体类型代替模板参数的过程叫做实例化**(instantiation)**,对于实例化模板参数的每种类型,都从模板中产生出一个不同的实体。
- 模板会被编译两次:
1.实例化之前:先检查模板代码,查看语法是否正确,这里会发现错误的语法,如缺少分隔符(;)等。
2.实例化期间:检查模板代码,查看是否所有的调用有效,在这里可能发现无效的调用,如实例化的类型不支持某些函数调用等。
1.5函数模板的实参演绎
函数模板的实参演绎:调用参数的类型构造自模板参数,所以模板参数和调用参数通常是相关的,它可以让你像调用普通函数一样调用函数模板。
1.6重载模板函数
重载:相同的函数名具有不同的函数定义(函数功能)
// 函数A
const int& Max(const int& nA, const int& nB)
{
return nA > nB ? nA : nB;
}
// 函数B
template <typename T>
const T& Max(const T& tA, const T& tB)
{
return tA > tB ? tA : tB;
}
// 函数C
template <typename T>
const T& Max(const T& tA, const T& tB, const T& tC)
{
return Max(Max(tA, tB), tC);
}
void TestFunction()
{
Max(7, 8, 9); // 调用函数C
Max(7, 8); // 调用函数A
Max(7.2, 2.7); // 调用函数B
Max("AA", "BB") // 调用函数B
Max('A', 3.7); // 调用函数A
}
上述案例中,最后一次函数函数调用为什么会调用函数A,原因在于模板不允许自动类型转化,所以在以上选择中只能调用普通函数。
函数模板重载原则:最好只改变那些需要改变的内容
- 改变参数的数目
- 显示的指定模板
1.7总结
- 函数模板为不同的模板参数提供了一个函数族
- 当传递模板实参的时候,可以根据实参的类型来对函数模板进行实例化(实参演绎)
- 可以显示指定模板参数,可以重载模板参数
- 函数模板重载原则:最好只改变那些需要改变的内容
- 一定要让函数模板的所有重载版本声明都为于它们被调用的位置之前
最后一点说明:一定要让函数模板的所有重载版本声明都为于它们被调用的位置之前
// 函数B
template <typename T>
const T& Max(const T& tA, const T& tB)
{
return tA > tB ? tA : tB;
}
// 函数C
template <typename T>
const T& Max(const T& tA, const T& tB, const T& tC)
{
return Max(Max(tA, tB), tC);
}
// 函数A
const int& Max(const int& nA, const int& nB)
{
return nA > nB ? nA : nB;
}
void TestFunction()
{
Max(7, 8, 9);
}
问题:在 TestFunction 函数执行时,函数A会被调用么,答案是不会,因为A函数的声明来得太迟了,函数C在执行过程中,首先回去找到函数B的声明,然后调用它。