目录
一、自动推导
1、概念
使用auto关键词声明变量类型,编译器自动推导出数据的类型(类似python中声明变量)
对比:
void test1() {
int a = 1;
double b = 1.3;
string c = "hello";
cout << a << " " << b << " " << c << endl;
cout << sizeof(a) << " " << sizeof(b) << " " << sizeof(c) << endl;
cout<<endl;
//对比:
auto a1 = 2;
auto b1 = 2.1;
auto c1 = "world";
cout << a1 << " " << b1 << " " << c1 << endl;
cout << sizeof(a1) << " " << sizeof(b1) << " " << sizeof(c1) << endl;
}
2、使用场景
1)函数指针
int myfun(int a,int b) {
return a + b;
}
void test2() {
//声明函数指针
int(*p)(int, int);
p = myfun;
cout << p(1, 2) << endl;
//auto自动推导
auto p1 = myfun;
cout << p1(3, 4) << endl;
}
结果:
3、注意事项
- 使用auto声明时必须赋初值
- 等号右边可以是数值、表达式、函数返回值
- 不可作函数形参
- 不能直接声明数组
- 不能定义类的非静态成员变量
二、函数模板
1、概念
函数模板是通用的函数描述,使用任意类型(泛型)描述函数,编译器根据传入的实参类型和模板生成函数定义(代码),此过程称为函数的实例化。与函数重载功能类似但更为简洁。
函数模板仅作为函数的描述,不具有实体,在实例化的时候才生成对应的函数空间。
2、例子
1)单个通用参数
//函数模板
template<typename anytype>
void myswap(anytype &a, anytype &b) {
anytype t = a;
a = b;
b = t;
}
void test3() {
int a = 1, b = 2;
myswap(a,b);
cout << a << " " << b << endl;
}
结果:
2)多个通用参数
//多个通用参数的函数模板
template<typename anytype1,typename anytype2>
void myfun1(anytype1 a, anytype2 b) {
cout << a << endl;
cout << b << endl;
}
void test5() {
int a = 1, b = 'A';
myfun1(a, b);
}
结果:
3)非通用的参数
template<typename T,int n>
T factorial(T t1) {
T t=t1;
for (int i = 0; i < n-1; i++) {
t = t * t1;
}
return t;
}
示例中
int n
是非通用的模板参数,使用模板函数时需要显示地指定参数类型,对于非通用的参数n
,指定n
的值即可,测试如下:
void test11() {
cout << factorial<int,3>(5) << endl;;
}
结果:
3、注意事项
- 类中可以使用函数模板,虚函数和析构函数不能用
- 传入的实参必须是相同的数据类型,如果不传入实参需手动指定数据类型
- 函数模板无法隐式转换数据类型,如需转换需手动指定数据类型,示例如下:
template<typename anytype>
anytype myadd(anytype a, anytype b) {
anytype c = a + b;
return c;
}
void test4() {
int a = 1;
char b = '2';
cout << myadd<int>(a, b) << endl;
cout<<myadd<char>(a,b) << endl;
cout << a + (int)b << endl;
cout << a + b << endl;
}
结果:
- 函数模板无法隐式转换数据类型,如需转换需手动指定数据类型
三、函数模板的具体化
函数模板的特例,调用时编译器优先匹配具体化的模板再匹配通用的函数模板
优先级对比:
1、具体化函数模板优先级高于通用函数模板
template <typename anytype>
void myprint(anytype a) {
cout << "通用型:" <<a<< endl;
}
//函数模板具体化
template<>
void myprint(int a) {
cout << "具体化:" <<a<< endl;
}
void test6() {
int a = 1;
char b = 'a';
myprint(a);
myprint(b);
}
结果:
2、普通函数优先级高于所有函数模板,但是若函数模板有更好的参数匹配,则函数模板高于普通函数:
template <typename anytype>
void myprint(anytype a) {
cout << "通用型:" <<a<< endl;
}
//函数模板具体化
template<>
void myprint(int a) {
cout << "具体化:" <<a<< endl;
}
//添加普通函数
void myprint(int a) {
cout << "普通:" << a << endl;
}
void test6() {
int a = 1;
char b = 'a';
myprint(a);
myprint(b);
}
结果:
传入字符型参数b,结果调用的是函数模板
3、函数调用时加空参数跳过普通函数强制执行函数模板:
void test6() {
int a = 1;
char b = 'a';
myprint<>(a);//加空参数
myprint(b);
}
结果:
四、函数模板分文件编写
函数的声明和定义可以在不同文件中实现,
- 普通函数和特例化的函数模板在头文件中声明,在源文件中定义。
- 通用型函数模板声明和特例化只能在同译文件中
头文件:
#include <iostream>
using namespace std;
//声明普通函数
void myprint_(int a);
//声明函数模板
template<typename anytype>
void myprint_(anytype a) {
cout << "通用型:" << a << endl;
}
//声明具体化函数模板
template<>
void myprint_(int a);
源文件:
#include <myhead.h>
//普通函数声明
void myprint_(int a) {
cout << "普通:" << a << endl;
}
//特例化声明
template <>
void myprint_(int a) {
cout << "特例化" << a << endl;
}
主函数:
void test7() {
myprint_(1);
myprint_<>(2);
myprint_('A');
}
结果:
五、自动推导的函数类型
1、类型说明符decltype
能够返回一个数据、表达式或函数的数据类型或引用,且在返回过程中不会发生表达式或函数的执行
int myfun2() {
cout << "hello world" << endl;
return 0;
}
void test8() {
int a = 1;
decltype(a) x1=1; cout << "x1=" << x1 << endl;
decltype(myfun2()) x2 = 2; cout << "x2=" << x2 << endl;
decltype(++a) x3 = ++a; cout << "x3=" << x3 << endl;
decltype(myfun2)* x4; x4 = myfun2; x4();
decltype((myfun2)) x5 = myfun2; x5();
}
结果:
2、自动推导的函数类型实现
template<typename anytype1,typename anytype2>
auto myadd2(anytype1 a, anytype2 b) -> decltype(a+b) {
auto t = a + b;
return t;
}
void test9() {
cout << myadd2(1, 2.3) << endl;
cout << myadd2(1, 'A') << endl;
}
注:C++14对函数类型推导规则进行了优化,简化写法:
template<typename anytype1,typename anytype2>
auto myadd2(anytype1 a, anytype2 b){...}
结果:
六、模板类
1、模板类的定义
模板类通用地描述类的数据类型,定义出来的 anytype 可以在类中的任意位置使用
template <class anytype>
class Mycla {
anytype a;
public:
Mycla(anytype a1) {
a = a1;
}
anytype get_a() {
return a;
}
};
2、使用模板类创建对象
需要显式地指定数据类型,代码含义:实例化 int型 的Mycla 类,并创建对象 obj1
void test10() {
Mycla<int> obj1(1);
cout << obj1.get_a() << endl;
}
结果:
3、注意事项
- 在指定多个通用参数时可以设置缺省的数据类型
template<class anytype1,class anytype2=char>
class Mycla2 {
anytype1 a;
anytype2 b;
public:
Mycla2(anytype1 a1, anytype2 b1) {
a = a1;
b = b1;
}
};
void test10() {
Mycla2<int> obj2(1,'A');
}
- 在类外实现成员函数
template<class T1,class T2=char>
class Mycla2 {
T1 a;
T2 b;
public:
Mycla2(T1 a1, T2 b1) {
a = a1;
b = b1;
}
T1 print_a();
T2 print_b();
};
//类外实现成员函数
template<class T1,class T2>
T1 Mycla2<T1, T2>::print_a() {
cout << a << endl;
return a;
}
template<class T1, class T2>
T2 Mycla2<T1, T2>::print_b() {
cout << b << endl;
return b;
}
void test10() {
Mycla2<int> obj2(1,'A');
obj2.print_a();
obj2.print_b();
}
结果:
- 使用 new 语句创建模板对象
template <class anytype>
class Mycla {
anytype a;
public:
Mycla(anytype a1) {
a = a1;
}
anytype get_a() {
return a;
}
};
void test10() {
Mycla<int>* obj = new Mycla<int>(3);
cout << obj->get_a() << endl;
delete(obj);
}
结果:
七、模板类的具体化
模板类的具体化和函数的具体化类似,可以在定义时将部分参数具体化,假设一个未具体化的模板类定义如下:
template <class T1,class T2>
class A {
T1 a;
T2 b;
};
1、部分具体化
template<class T1>
class A<T1, int> {
T1 a;
int b;
};
2、完全具体化
template<>
class A<int, char> {
int a;
char b;
};
需要注意具体化的前提是要先定义未具体化的类模板,否则不存在具体化一说,和函数模板的具体化是一样的。