函数模板
什么是模板: 把类型当做未知量,可以忽略类型影响
#include<iostream>
using namespace std;
int Max(int a, int b)
{
return a > b ? a : b;
}
string Max(string a, string b)
{
return a > b ? a : b;
}
//引入模板这个东西
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
int main()
{
return 0;
}
声明模板的语法
//单个未知类型
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号
Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
//可以多个未知类型
template <typename _Ty1,typename _Ty2>
void print(_Ty1 one ,_Ty2 two)
{
cout<<one<<endl;
cout<<two<<endl;
}
//typename 可以换成class
template <class T>
void print(T a)
{
cout<<a<<endl;
}
调用函数模板
-
? 隐式调用 : 正常的函数传参即可调用 #include<iostream>
using namespace std;
int Max(int a, int b)
{
return a > b ? a : b;
}
string Max(string a, string b)
{
return a > b ? a : b;
}
//引入模板这个东西
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
int main()
{
//隐式调用
cout << Max(1, 2) << endl;
cout << Max("string", "string")<<endl;
cout << Max(1.1, 2.3 << endl;
return 0;
}
-
? 显示调用: 函数名<类型名>(参数) #include<iostream>
#include<string>
using namespace std;
int Max(int a, int b)
{
return a > b ? a : b;
}
string Max(string a, string b)
{
return a > b ? a : b;
}
//引入模板这个东西
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
//_Ty =string a="abc" b="abc"
template <class _Ty1, class _Ty2>
void print(_Ty1 one ,_Ty2 two)
{
cout << one << endl;
cout << two << endl;
}
int main()
{
//隐式调用
cout << Max(1, 2) << endl;
cout << Max("string", "string")<<endl;
cout << Max(1.1, 2.3) << endl;
//显示调用
cout << Max<string>("abc", "abd") << endl;
print<string, string>("string1", "string2");
print<string, int>("string1", 123);
return 0;
}
函数模板的两种形态
-
? 普通函数当做函数模板 -
? 类的成员函数是函数模板 #include<iostream>
#include<string>
using namespace std;
int Max(int a, int b)
{
return a > b ? a : b;
}
string Max(string a, string b)
{
return a > b ? a : b;
}
//引入模板这个东西
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
//_Ty =string a="abc" b="abc"
template <class _Ty1, class _Ty2>
void print(_Ty1 one ,_Ty2 two)
{
cout << one << endl;
cout << two << endl;
}
class MM
{
public:
template <class _Ty>
void print(_Ty data)
{
cout << data << endl;
}
template <class _Ty>
void printData(_Ty data);
protected:
string name;
int age;
};
//在类外实现的时候不能省略template这一块
template <class _Ty>
void MM::printData(_Ty data)
{
cout << data << endl;
}
int main()
{
//隐式调用
cout << Max(1, 2) << endl;
cout << Max("string", "string")<<endl;
cout << Max(1.1, 2.3) << endl;
//显示调用
cout << Max<string>("abc", "abd") << endl;
print<string, string>("string1", "string2");
print<string, int>("string1", 123);
//类照曝光额成员函数是函数模板
MM mm;
mm.print(123);
mm.print<string>("ILoveyou");
mm.printData(12345);
return 0;
}
函数模板特殊的写法
-
? 缺省写法 #include<iostream>
#include<string>
using namespace std;
int Max(int a, int b)
{
return a > b ? a : b;
}
string Max(string a, string b)
{
return a > b ? a : b;
}
//引入模板这个东西
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
//_Ty =string a="abc" b="abc"
template <class _Ty1, class _Ty2>
void print(_Ty1 one ,_Ty2 two)
{
cout << one << endl;
cout << two << endl;
}
class MM
{
public:
template <class _Ty>
void print(_Ty data)
{
cout << data << endl;
}
template <class _Ty>
void printData(_Ty data);
protected:
string name;
int age;
};
//在类外实现的时候不能省略template这一块
template <class _Ty1>
void MM::printData(_Ty data)
{
cout << data << endl;
}
template <class _Ty1, class _Ty2 = int>
void printData(_Ty1 one, _Ty2 two)
{
cout << one << "\t" << two << endl;
}
void testFunc()
{
printData("string", 1234);
//函数模板的缺省,显示调用,可以不用传类型,但是参数是不能少的
printData<string>("ILoveyou", 1234);
}
int main()
{
//隐式调用
cout << Max(1, 2) << endl;
cout << Max("string", "string")<<endl;
cout << Max(1.1, 2.3) << endl;
//显示调用
cout << Max<string>("abc", "abd") << endl;
print<string, string>("string1", "string2");
print<string, int>("string1", 123);
//类照曝光额成员函数是函数模板
MM mm;
mm.print(123);
mm.print<string>("ILoveyou");
mm.printData(12345);
//模板函数可不可缺省
return 0;
}
-
? 存在常量类型 #include<iostream>
#include<string>
using namespace std;
int Max(int a, int b)
{
return a > b ? a : b;
}
string Max(string a, string b)
{
return a > b ? a : b;
}
//引入模板这个东西
template <typename _Ty>//告诉编译器 下面代码用到一个位置类型叫做_Ty _Ty 随便改 ,就是类型代号
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
//_Ty =string a="abc" b="abc"
template <class _Ty1, class _Ty2>
void print(_Ty1 one ,_Ty2 two)
{
cout << one << endl;
cout << two << endl;
}
class MM
{
public:
template <class _Ty>
void print(_Ty data)
{
cout << data << endl;
}
template <class _Ty>
void printData(_Ty data);
protected:
string name;
int age;
};
//在类外实现的时候不能省略template这一块
template <class _Ty1>
void MM::printData(_Ty data)
{
cout << data << endl;
}
template <class _Ty1, class _Ty2 = int>
void printData(_Ty1 one, _Ty2 two)
{
cout << one << "\t" << two << endl;
}
//存在传常量写法
//size_t:unsigned int 的别名
template <class _Ty1,size_t size=3>
void printArray(_Ty1 array)//_Ty1 = int* size=3
{
for (int i = 0; i < size; i++)
{
cout << array[i];
}
cout << endl;
}
void testFunc()
{
printData("string", 1234);
//函数模板的缺省,显示调用,可以不用传类型,但是参数是不能少的
printData<string>("ILoveyou", 1234);
int array[3] = { 1, 2, 3 };
//没有做缺省必须显示调用
printArray<int*,3>(array);
//做了缺省可以隐式调用
printArray(array);
//不能传入变量,只能传入常量,函数模板如果存在变量的情况下
/*int size = 3;
printArray<int*, size>(array);*/
}
int main()
{
//隐式调用
cout << Max(1, 2) << endl;
cout << Max("string", "string")<<endl;
cout << Max(1.1, 2.3) << endl;
//显示调用
cout << Max<string>("abc", "abd") << endl;
print<string, string>("string1", "string2");
print<string, int>("string1", 123);
//类照曝光额成员函数是函数模板
MM mm;
mm.print(123);
mm.print<string>("ILoveyou");
mm.printData(12345);
//模板函数可不可缺省
return 0;
}
类模板
如何生成一个类模板
template<class _Ty>
class MM
{
public:
protected:
}
//只要被template修饰就是一个模板类,用没用未知类型没有关系
类模板调用
-
必须采用显式调用 #include <iostream>
using namespace std;
//template <>
//class Data
//{
//
//};
template <class _Ty>
class MM
{
public:
protected:
};
int main()
{
//必须采用显示调用
MM<int> mm;
MM<string> mm2;
MM<double> mm3;
//MM mm;错误的!
return 0;
}
-
类模板不是一个实际类型,所以所有用到类名的地方都需要使用: 类名<未知类型> 方式使用 #include <iostream>
using namespace std;
//template <>
//class Data
//{
//
//};
template <class _Ty>
class MM
{
public:
MM(){};
MM(string name):name(name){}
void print();
protected:
string name;
};
//在类外实现
template <class _Ty>
void MM<_Ty>::print()
{
cout << "类模板" << endl;
}
template <class _Ty>
class Girl :public MM<_Ty>
{
public:
Girl(string name) :MM<_Ty>(name)
{
}
protected:
};
int main()
{
//必须采用显示调用
MM<int> mm;
MM<string> mm2;
MM<double> mm3;
//MM mm;错误的!
Girl<int> girl("Loveyou");
girl.print();
return 0;
}
-
多文件中,类模板 中的声明和实现一定在一起的,不能分开写。 #include <iostream>
using namespace std;
//template <>
//class Data
//{
//
//};
template <class _Ty>
class MM
{
public:
MM(){};
MM(string name):name(name){}
void print();
protected:
string name;
};
//在类外实现
template <class _Ty>
void MM<_Ty>::print()
{
cout << "类模板" << endl;
}
template <class _Ty>
class Girl :public MM<_Ty>
{
public:
Girl(string name) :MM<_Ty>(name)
{
}
protected:
};
template <class _Ty1,class _Ty2>
class Data
{
public:
Data(_Ty1 one, _Ty2 two) :one(one), two(two){}
void print();
protected:
_Ty1 one;
_Ty2 two;
};
template <class _Ty1, class _Ty2>
void Data<_Ty1, _Ty2>::print()
{
cout << one << endl;
cout << two << endl;
}
int main()
{
//必须采用显示调用
MM<int> mm;
MM<string> mm2;
MM<double> mm3;
//MM mm;错误的!
Girl<int> girl("Loveyou");
girl.print();
Data<string, int> mmInfo("小芳",19);
mmInfo.print();
Data<int, int> data(12, 10);
data.print();
return 0;
}
自定义类型当做模板参数
基本自定义类型
自定义类型也是一个模板
模板传入自定义类型,关键点就在于重载运算符
#include<iostream>
#include<string>
using namespace std;
class MM
{
public:
MM(string name, int age) :name(name), age(age){}
friend ostream& operator<<(ostream& out, MM& mm)
{
out << mm.name << " " << mm.age;
return out;
}
bool operator>(MM& mm) const
{
return this->age > mm.age;
}
protected:
string name;
int age;
};
template <class _Ty>
void print(_Ty one)
{
//错误 1 error C2679: 二进制“<<”: 没有找到接受“std::string”类型的右操作数的运算符(或没有可接受的转换) c:\users\administrator\desktop\mycjiajiapro\consoleapplication11\consoleapplication11\源.cpp 17 1 ConsoleApplication11
cout << one << endl;
}
template <class _Ty>
_Ty Max(_Ty a, _Ty b)
{
//错误 5 error C2784: “bool std::operator >(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)”: 未能从“MM”为“const std::reverse_iterator<_RanIt> &”推导 模板 参数 c:\users\administrator\desktop\mycjiajiapro\consoleapplication11\consoleapplication11\源.cpp 37 1 ConsoleApplication11
return a > b ? a : b;
}
int main()
{
//函数模板传入自定义类型
print(12);
print<string>("string");
print(MM("mm", 19));
MM xiaoF("小芳", 18);
MM xiaoL("小丽", 28);
MM result = Max<MM>(xiaoF, xiaoL);
//MM result = Max(xiaoF, xiaoL);函数模板可以隐式调用
cout << result << endl;
return 0;
}
#include <iostream>
using namespace std;
class MM
{
public:
MM(string name, int age) :name(name), age(age) {}
friend ostream& operator<<(ostream& out, const MM& mm)
{
out << mm.name << " " << mm.age;
return out;
}
bool operator>(MM& mm) const
{
return this->age > mm.age;
}
protected:
string name;
int age;
};
template <class _Ty>
void print(_Ty one)
{
//error C2679: 二进制“<<”: 没有找到接受“_Ty”类型的右操作数的运算符(或没有可接受的转换)
cout << one << endl;
}
template <class _Ty>
_Ty Max(_Ty a, _Ty b)
{
//rror C2676: 二进制“>”:“_Ty”不定义该运算符或到预定义运算符可接收的类型的转换
return a > b ? a : b;
}
template <class _Ty>
class Node
{
public:
Node(_Ty data, Node<_Ty>* next) :data(data), next(next) {}
_Ty getData()
{
return data;
}
Node<_Ty>* getNext()
{
return next;
}
protected:
_Ty data;
Node<_Ty>* next;
//正常写法:Node* next;
};
template <class _Ty>
class List
{
public:
List()
{
headNode = nullptr;
}
void insertList(_Ty data)
{
headNode = new Node<_Ty>(data, headNode);
}
void printList()
{
Node<_Ty>* pmove = headNode;
while (pmove != nullptr)
{
//error C2679: 二进制“<<”: 没有找到接受“_Ty”类型的右操作数的运算符(或没有可接受的转换)
cout << pmove->getData() << endl;
pmove = pmove->getNext();
}
cout << endl;
}
protected:
Node<_Ty>* headNode;
};
void testList()
{
List<int> list;
list.insertList(1);
list.insertList(2);
list.insertList(3);
list.printList();
List<MM> mmList;
mmList.insertList(MM("小芳", 18));
mmList.insertList(MM("小丽", 28));
mmList.insertList(MM("小美", 38));
mmList.printList();
}
int main()
{
//函数模板传入自定义类型
print(12);
print<string>("string");
print(MM("mm", 19));
MM xiaoF("小芳", 18);
MM xiaoL("小丽", 28);
MM result = Max<MM>(xiaoF, xiaoL);
//MM result = Max(xiaoF, xiaoL); 函数模板可以隐式调用
cout << result << endl;
testList();
return 0;
}
模板嵌套
明白类型是什么即可,适当可以借用using语法起别名 简化代码
#include <iostream>
using namespace std;
template <class _Ty1, class _Ty2>
class MM
{
public:
MM(_Ty1 one, _Ty2 two) :one(one), two(two) {}
friend ostream& operator<<(ostream& out, const MM& mm)
{
out << mm.one << " " << mm.two;
return out;
}
protected:
_Ty1 one;
_Ty2 two;
};
template <class _Ty1, class _Ty2>
class Data
{
public:
Data(_Ty1 one, _Ty2 two) :one(one), two(two) {}
void print()
{
cout << one << " " << two << endl;
}
protected:
_Ty1 one;
_Ty2 two;
};
void testFunc()
{
//_Ty1类型是:MM<string,int>
//_Ty2类型是:MM<double,double>
Data<MM<string, int>, MM<double, double>>
data(MM<string, int>("小芳", 18), MM<double, double>(89, 56));
data.print();
//上面两行 等效下面四行代码
MM<string, int> mmData("小芳", 18);
MM<double, double> mmScore(89, 56);
Data<MM<string, int>, MM<double, double>> mData(mmData, mmScore);
mData.print();
}
template <class _Ty>
void print(_Ty data)
{
cout << data << endl;
}
int main()
{
//隐式调用
print(MM<string, int>("小芳", 32));
//显示调用
//类型:MM<string, int>
print<MM<string, int>>(MM<string, int>("小美", 238));
//起别名简化代码
using MMType = MM<string, int>;
print<MMType>(MMType("小美", 238));
testFunc();
return 0;
}
函数模板重载
模板和普通函数 ,调用函数函数类型一致情况 优先调用普通函数
两个模板同时成立,优先调用类型相似度高的那个
类模板特化
局部特化
完全特化
|