模板以template关键字和一个形参表开头
参数至少是有一个模板类型
1 #include <iostream> 2 using namespace std; 3 4 //T通用数据类型 5 template <typename T> 6 T MAX(T *p, const int n) 7 { 8 T maxdata(p[0]); 9 10 for (int i = 0; i < n; i++) 11 { 12 if (maxdata < p[i]) 13 { 14 maxdata = p[i]; 15 } 16 } 17 18 return maxdata; 19 } 20 21 void main() 22 { 23 int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; 24 double b[10] = { 1,2,3,4,5,6,7,8,9,10 }; 25 26 std::cout << MAX(a, 10) << std::endl; 27 std::cout << MAX(b, 10) << std::endl; 28 29 system("pause"); 30 }
函数参数不允许使用自动变量
//error C3533: 参数不能为包含“auto”的类型
1 #include <iostream> 2 using namespace std; 3 4 int putnum(auto num)//error C3533: 参数不能为包含“auto”的类型 5 { 6 7 } 8 9 void main() 10 { 11 12 system("pause"); 13 }
函数模板中可以使用inline
1 #include <iostream> 2 using namespace std; 3 4 template <class T> 5 inline T getX3(T x) 6 { 7 return x*x*x; 8 } 9 10 void main() 11 { 12 std::cout << getX3(1 + 2) << std::endl;//27 13 14 system("pause"); 15 }
函数模板根据类型覆盖
//模板为空,明确类型
template <>
void swap1(info &info1, info &info2)
{
std::cout << "特有函数模板" << std::endl;
info temp = info1;
info1 = info2;
info2 = temp;
}
不写上T
1 #include <iostream> 2 using namespace std; 3 4 //函数模板实现通用,可以根据自有数据类型,进行优化 5 //结构体可以直接赋值 6 //所有成员都是公有的类型可以赋值 7 8 struct info 9 { 10 char name[100]; 11 double db; 12 int data; 13 }; 14 15 template <typename T> 16 void swap1(T &a, T &b) 17 { 18 std::cout << "通用函数模板" << std::endl; 19 T temp = a; 20 a = b; 21 b = temp; 22 } 23 24 //模板为空,明确类型 25 template <> 26 void swap1(info &info1, info &info2) 27 { 28 std::cout << "特有函数模板" << std::endl; 29 info temp = info1; 30 info1 = info2; 31 info2 = temp; 32 } 33 34 void main() 35 { 36 info info1 = { "hello",20.9,10 }; 37 info info2 = { "world",9.2,1 }; 38 39 swap1(info1, info2);//交换两个结构体 40 41 std::cout << info1.name << " " << info1.db << " " << info1.data << std::endl; 42 std::cout << info2.name << " " << info2.db << " " << info2.data << std::endl; 43 44 system("pause"); 45 }
//如果类有私有成员变量,不可以用大括号初始化
//类的对象之间默认是可以直接赋值
//类、结构体都有一个默认赋值操作=浅拷贝
//深拷贝用得最多,函数模板的覆盖
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <iostream> 3 using namespace std; 4 5 //如果类有私有成员变量,不可以用大括号初始化 6 //类的对象之间默认是可以直接赋值 7 //类、结构体都有一个默认赋值操作=浅拷贝 8 //深拷贝用得最多,函数模板的覆盖 9 10 class info 11 { 12 private: 13 int num; 14 public: 15 char name[100]; 16 char *p; 17 int data; 18 void set(int X) 19 { 20 this->num = X; 21 } 22 int get() 23 { 24 return this->num; 25 } 26 }; 27 28 template <typename T> 29 void swap1(T &a, T &b) 30 { 31 std::cout << "通用函数模板" << std::endl; 32 T temp = a; 33 a = b; 34 b = temp; 35 } 36 37 //模板为空,明确类型 38 template <> 39 void swap1(info &info1, info &info2) 40 { 41 std::cout << "特有函数模板" << std::endl; 42 info temp = info1; 43 info1 = info2; 44 info2 = temp; 45 } 46 47 //函数,对一个对象进行深拷贝,需要自己函数模板重载 48 49 void main() 50 { 51 info info1; 52 info info2; 53 54 std::strcpy(info1.name, "hello"); 55 std::strcpy(info2.name, "world"); 56 info1.p = new char[10]; 57 std::strcpy(info1.name, "info1.p"); 58 info2.p = new char[10]; 59 std::strcpy(info2.name, "info2.p"); 60 info1.data = 102; 61 info2.data = 201; 62 info1.set(89); 63 info2.set(98); 64 65 swap1(info1, info2); 66 67 std::cout << info1.name << " " << info1.p << info1.data << " " << info1.get() << " " << std::endl; 68 std::cout << info2.name << " " << info1.p << info2.data << " " << info2.get() << " " << std::endl; 69 70 system("pause"); 71 }
//函数模板可以对类型进行优化重载,根据类型会覆盖
//如果仍然要使用模板函数,需要实例化
显式比较准则
函数模板名<模板参数>(参数列表)
add<int>(a, b);//T add,实例化
add<int>(db1, db2);//T add,实例化
add<double>(db1, db2);//T add,实例化
1 #include <iostream> 2 using namespace std; 3 4 //函数模板可以对类型进行优化重载,根据类型会覆盖 5 //如果仍然要使用模板函数,需要实例化 6 7 template <class T>//函数模板 8 T add(T a, T b) 9 { 10 std::cout << "T add" << std::endl; 11 return a + b; 12 } 13 14 int add(int a, int b)//一般函数 15 { 16 std::cout << "int add" << std::endl; 17 return a + b; 18 } 19 20 void main() 21 { 22 int a(10), b(20); 23 24 double db1(10.9), db2(10.8); 25 26 add(a, b);//int add 27 28 add(db1, db2);//T add 29 30 add<int>(a, b);//T add,实例化 31 32 add<int>(db1, db2);//T add,实例化 33 34 add<double>(db1, db2);//T add,实例化 35 36 system("pause"); 37 }
函数可变参数通用类型,函数模板
//通用可变参数模板
//可处理不限定个数的参数,处理不同类型
//根据不同的需求,采用不同的设计
//设计可以修改原来的数据的,不要加上const,要引用,void showall(const &value, Args &...args)
//设计可以修改副本,不要const,不要引用,void showall(T value, Args...args)
//设计不可以修改原来的数据,且不能修改副本void showall(const T value, const Args...args)
//设计引用原来的数据,但不可以修改void showall(const T &value, const Args &...args)
1 #include <iostream> 2 using namespace std; 3 4 //通用可变参数模板 5 //可处理不限定个数的参数,处理不同类型 6 7 void showall()//空函数,必须保留,作用:接口作用,最后结束递归 8 { 9 10 } 11 12 //根据不同的需求,采用不同的设计 13 //设计可以修改原来的数据的,不要加上const,要引用,void showall(const &value, Args &...args) 14 //设计可以修改副本,不要const,不要引用,void showall(T value, Args...args) 15 //设计不可以修改原来的数据,且不能修改副本void showall(const T value, const Args...args) 16 //设计引用原来的数据,但不可以修改void showall(const T &value, const Args &...args) 17 18 template <typename T, typename...Args> 19 void showall(const T &value, const Args &...args) 20 { 21 std::cout << value << std::endl; 22 showall(args...);//继续传递,递归 23 std::cout << std::endl; 24 } 25 26 void main() 27 { 28 int num1(10), num2(9), num3(11); 29 30 double db1(10.8), db2(10.9); 31 32 char str[40] = "hello"; 33 34 char ch = 'A'; 35 36 showall(num1); 37 38 showall(num1, num2, num3); 39 40 showall(db1, db2, num1, ch); 41 42 showall(db1, db2, num1, ch, str); 43 44 system("pause"); 45 }
函数模板重载,array数组作为参数
1 #include <iostream> 2 #include <array> 3 using namespace std; 4 5 template <typename T> 6 void showarray(std::array<T, 10> myarray, int n)//对象数组 7 { 8 std::cout << "对象数组" << std::endl; 9 for (int i = 0; i < n; i++) 10 { 11 std::cout << myarray[i] << " "; 12 } 13 std::cout << std::endl; 14 } 15 16 template <typename T> 17 void showarray(std::array<T *, 10> myarray, int n)//指针数组 18 { 19 std::cout << "指针数组" << std::endl; 20 for (int i = 0; i < n; i++) 21 { 22 std::cout << *myarray[i] << " "; 23 } 24 std::cout << std::endl; 25 } 26 27 void main() 28 { 29 std::array<int, 10>intarray = { 1,2,3,4,5,6,7,8,9,10 };//创建一个数组,数组的元素类型是int 30 31 std::array<int *, 10>pintarray;//创建一个数组,数组的元素类型是int * 32 33 std::array<int **, 10>ppintarray;//创建一个数组,数组的元素类型是int ** 34 35 for (int i = 0; i < 10; i++) 36 { 37 pintarray[i] = &intarray[i];//赋值 38 } 39 40 for (int i = 0; i < 10; i++) 41 { 42 ppintarray[i] = &pintarray[i];//赋值 43 } 44 45 showarray(intarray, 10);//对象数组 46 47 showarray(pintarray, 10);//指针数组 48 49 showarray(ppintarray, 10);//指针数组 50 51 system("pause"); 52 }
面试:
typename与class区别
关键字typename作为类型前的标识符号
1 template <class T> 2 class MyClass 3 { 4 typename T::SubType * ptr; 5 //typename指出SubType是T中定义的一个类型,因此ptr是一个指向T::SubType的指针 6 //如果不加上typename,表达式被认为是T中的静态成员SubType和ptr的乘积 7 };
C++的一般规则是,除了以typename修饰以外,template内的任何标识符号都被视为一个值value,而非一个类型type
typename的第二个作用:在模板声明中替换关键字class
template <typename T>
class MyClass;
软件工程规范,用typename,不用class