C++模板编程

目录

一,模板函数、模板类

1,模板函数

2,模板类

(1)可继承性

(2)友元

(3)静态成员

二,模板参数

1,多类型参数

2,默认类型

3,模板函数的类型推导

4,类参数

5,非类型参数

三,具体化、实例化、特化

1,具体化

2,隐式实例化

3,显式实例化

4,特化

5,偏特化

6,经典应用

四,函数重载 待更新

1,模板间重载

2,普通函数和模板函数间重载

五,仿函数与模板编程

1,模板函数

2,模板类


一,模板函数、模板类

1,模板函数

像max这种函数,对于参数类型,计算逻辑是一样的,只是入参和返回值类型不同,就可以写成模板函数。

示例:

#include<iostream>
using namespace std;

template<typename T>
T maxmax(T a, T b)
{
	return (a > b ? a : b) + 1;
}

int main()
{
	cout << maxmax(1, 2) << endl;
	cout << maxmax(1.3, 1.5) << endl;
	cout << maxmax("as", "zx");
	return 0;
}

输出:

3
2.5
s

但是,不能这么调用:maxmax(1.3,1),这样写会报错,有重载歧义。

2,模板类

和模板函数语法差不多。

示例:

#include<iostream>
using namespace std;

template<typename T>
class GetMax
{
public:
	T a;
	T b;
	GetMax(T a, T b)
	{
		this->a, this->b = b;
	}
	T getMax()
	{
		return a > b ? a : b;
	}
};

int main()
{
	int a = 1;
	cout << GetMax<double>(a, 2.3).getMax();
	return 0;
}

有个很重要的区别就是,模板类在调用的时候必须显示的指明类型参数,

所以这里就像普通函数一样,会隐式地把int类型的数转换为double的数。

(1)可继承性

模板类可以继承模板类,模板类可以继承非模板类,

非模板类可以继承模板类,非模板类可以继承非模板类。

(2)友元

友元的使用,对于模板类和非模板类是一样的。

(3)静态成员

对于模板类中的静态成员,每个模板具体化都拥有独立的静态数据域拷贝。

二,模板参数

1,多类型参数

要实现有不同数据类型的入参的函数,就需要多个模板参数。

示例:

#include<iostream>
using namespace std;

template<typename T1,typename T2>
T1 maxmax(T1 a, T2 b)
{
	return (a > b ? a : b) + 1;
}

int main()
{
	cout << maxmax(1, 2) << endl;
	cout << maxmax(1.3, 1.5) << endl;
	cout << maxmax(1.3, 1) << endl;
	cout << maxmax("as", "zx");
	return 0;
}

输出:

3
2.5
2.3
s

示例:

#include<iostream>
using namespace std;

template<typename T1,typename T2>
class GetMax
{
public:
	T1 a;
	T2 b;
	GetMax(T1 a, T2 b)
	{
		this->a, this->b = b;
	}
	T1 getMax()
	{
		return a > b ? a : b;
	}
};

int main()
{
	int a = 1;
	cout << GetMax<int, double>(a, 3.3).getMax() << endl;
	cout << GetMax<double,int>(a, 3.3).getMax();
	return 0;
}

输出:

3
3

2,默认类型

template<typename T1 = double>
void f(T1 a)
{
	cout << a;
}

int main()
{
	int a = 1;
	f(a);
	f(1.5);
    return 0;
}

这个例子太简单了,看起来提供默认类型并没有什么用。

模板类定义时,类型参数也可以指定默认类型。

template<typename T=int>
class MyClass
{
public:
	T x;
};

int main() {
	MyClass<> cs;
	return 0;
}

3,模板函数的类型推导

 我在用泛型编程写二维vector的排序模板时,写出这样一个代码:

//vector的字典序比较,v1<v2是true,v1>=v2是false
template<typename T>
bool cmp(vector<T>&v1,vector<T>&v2)
{
    for(int i=0;i<v1.size()&&i<v2.size();i++)
    {
        if(v1[i]!=v2[i])return v1[i]<v2[i];
    }
    return v1.size()<v2.size();
}
//vector的字典序排序
template<typename T>
void sortVector(vector<vector<T>>&v)
{
    sort(v.begin(),v.end(),cmp);
}

编译结果:

1>          c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(3802) : 参见“std::sort”的声明
1>c:\users\z00454773\documents\visual studio 2010\projects\20191228.cpp\20191228.cpp\csimsgeek.cpp(273): error C2780: “void std::sort(_RanIt,_RanIt)”: 应输入 2 个参数,却提供了 3 个

这就很奇怪了,一般在sort里面用自定义排序函数,就是加函数指针啊!

很快,我就想到了,这里的cmp是模板函数,它是需要根据类型参数来实例化的。

也就是说,模板函数直接调用是可以自动推导类型的,但是如果要用做函数指针的话,需要传入类型参数才能实例化

正确代码:

//vector的字典序排序
template<typename T>
void sortVector(vector<vector<T>>&v)
{
    sort(v.begin(),v.end(),cmp<T>);
}

4,类参数

类型参数除了可以是任意类型,也可以限定只能是某种class类型。

template <class A>
class PickX
{
public:
	int f(A p)
	{
		return p.x;
	}
};

5,非类型参数

在定义模板类时,参数列表除了类型参数还可以有变量参数。

示例:

#include<iostream>
using namespace std;

template<typename T,int len>
class Num
{
public:
	Num(T a)
	{
		this->num[0] = a;
	}
	T get()
	{
		return num[0];
	}
private:
	T num[len];
};

int main()
{
	cout << Num<int, 1>(2.3).get();
	return 0;
}

输出:

2

注意,创建模板类实例时,变量参数只能传常量,不能传变量,即使模板类中没有使用这个参数也是这样。

三,具体化、实例化、特化

1,具体化

模板代码本身是不能编译的,要指定类型生成具体代码之后才能编译。

具体化分为2种,一种是实例化,内容和模板一致,一种是特化,内容往往和模板不一致

2,隐式实例化

使用时根据类型推导进行隐式实例化

#include<iostream>
using namespace std;

template<typename T>
T maxmax(T a, T b)
{
	return (a > b ? a : b) + 1;
}

int main()
{
	cout << maxmax(1, 2) << endl;
	cout << maxmax(1.3, 1.5) << endl;
	cout << maxmax("as", "zx");
	return 0;
}

这里隐式实例化为3种类型,整数,浮点数,字符串。

3,显式实例化

#include<iostream>
using namespace std;

template<typename T>
T maxmax(T a, T b)
{
	return (a > b ? a : b) + 1;
}
template int maxmax(int a, int b);  //

int main()
{
	cout << maxmax(1, 2) << endl;
	cout << maxmax(1.3, 1.5) << endl;
	cout << maxmax("as", "zx");
	return 0;
}

4,特化

特化指的是和模板签名一致,但并非实例化的代码。

#include<iostream>
using namespace std;

template<typename T>
T maxmax(T a, T b)
{
	return (a > b ? a : b) + 1;
}
int maxmax(int a, int b)
{
	return 0;
}

int main()
{
	cout << maxmax(1, 2) << endl;
	cout << maxmax(1.3, 1.5) << endl;
	cout << maxmax("as", "zx");
	return 0;
}

5,偏特化

偏特化指的是多类型参数的情况下,部分类型进行特化,部分类型仍然保持模板类型。

偏特化代码可以理解成介于模板代码和特化代码的中间状态,也可以理解成是特化的一种。

6,经典应用

参考enable_if

四,函数重载 待更新

1,模板间重载

template<typename T1>
void f(T1 a)
{
	cout << 111;
}
template<typename T1, typename T2>
void f(T1 a, T2 b)
{
	cout << 222;
}
template<typename T1, typename T2>
void f(T1 a, T2 b, int c)
{
	cout << 333;
}
template<typename T1, typename T2>
void f(T1 a, T2 b, double c)
{
	cout << 4444;
}

int main()
{
	int a = 1, b = 2;
	f(a);
	f(a, b);
	f(a, b, 1);
	f(a, b, 1.5);
	return 0;
}

输出:1112223334444

2,普通函数和模板函数间重载

待更新

五,仿函数与模板编程

本章讨论,模板函数或者模板类以函数指针为形参,以仿函数为实参的情形。

1,模板函数

示例:

#include<iostream>
using namespace std;

int fun()
{
	return 2;
}

class FUN
{
public:
	int operator()()
	{
		return 3;
	}
};

class FUN2
{
public:
	int fun2()
	{
		return 3;
	}
};

template <class A>
int f(A p)
{
	return p();
}

int main()
{
	cout << f(fun) << "  " << f(FUN()) << "  ";
	//cout << f(FUN2());  错误
	//cout << f(FUN2().fun2());   错误
	return 0;
}

输出:

2  3

可以看出,当我们这样实现模板函数时,既可以传入普通函数指针,也可以传入仿函数类对象。

如果是普通类,无论传入对象还是成员函数都是错的。

2,模板类

如果是模板类,就只能传入仿函数类对象,不能传入普通函数。

示例:

#include<iostream>
using namespace std;

class FUN
{
public:
	int operator()()
	{
		return 3;
	}
};

template <class A>
class classf
{
public:
	int f(A p)
	{
		return p();
	}
};

int main()
{
	cout << classf<FUN>().f(FUN());
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值