template<class 模板参数>
class 类名 {
// 类定义
};
template<typename 模板参数>
class 类名 {
// 类定义
};
其中: template是声明类模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个,可以是类型参数 ,也可以是非类型参数。类型参数由关键字class或typename及其后面的标识符构成。非类型参数由一个普通参数构成,代表模板定义中的一个常量。
一般情况下,类模板的声明和实现在一个头文件内完成。如果采用声明实现分离的方式,在.h文件中声明,在.hpp文件中实现,使用该类模板时include目标.hpp文件。
Example01
// mytemplate.h
template<class T>
class MathOp {
public:
T add(T &a, T &b);
};
// mytemplate.hpp
#include "mytemplate.h"
template<class T>
T MathOp<T>::add(T &a, T &b)
{
T res = a + b;
return res;
}
// main.cpp
#include
#include "mytemplate.hpp"
int main(int argc, char** argv)
{
MathOp<int> op;
int a = 1;
int b = 2;
auto res = op.add(a, b);
std::cout << "1 + 2 = " << res << std::endl;
return 0;
}
// type为类型参数,width为非类型参数
template<class type, int width>
typedef string type;
template <class type, int width>
class Graphics {
type node; //* node 不是string类型
typedef double type; ///! error: 成员函数不能与模板参数type同名
};
template <class T, class T> ///! error:重复使用名为T的参数
class Rect;
template <class T> //* 参数名"T"在不同模板间可以重复使用
class Round;
/// MyStack声明都引用同一个类模板的声明
template <class T>
class MyStack;
template <class U>
class MyStack;
template <class Tp>
class MyStack {
//* 模板定义中智能引用名字"Tp",不能引用"T"和"U"
};
template <class T, int size = 16>
class MyStack;
template <typename T>
class Graphics {
T* next; //* 在类模板自己的定义中不需要指定完整模板参数表
};
template <typename T>
void show(Graphics<T>& g)
{
Graphics<T>* pg = &g; //* 必须指定完整的模板参数表
}
从通用的类模板定义中生成类的过程称为模板实例化
//* T是一个形参,同类型的实参值被提供给该形参
//* 指定的每个不同类型值都创建一个新类
template <typename T>
class Graphics {
T m_value;
};
// 类实例化
//* T被指定为int
class Graphics {
int m_value;
};
//* T被指定为double
class Graphics {
double m_value;
};
//* T被指定为string
class Graphics {
string m_value;
};
类模板实例化分为显示实例化和隐士实例化
template class Stack<int>; //将类模板实例化为一个处理int类型的Stack类
Stack<char> charStack; // 先实例化一个CharStack类(名字由编译器按规则生成),然后用CharStack char Stack;创建一个对象
Stack<int> intStack; // 实例化一个IntStack类,在调用IntStack intStack;创建一个对象
类模板实例化的时机
#include
template <typename T>
class Graphics {
// body
};
void func(Graphics<char>); // 函数声明,不需要实例化
class Rect {
Graphics<double>& rsd; // 声明一个类模板引用,不需要实例化
Graphics<int> si; // si是Graphics类型的对象,需要实例化类模板
};
void func(Graphics<char> p)
{
// todo
}
int main(int argc, char** argv)
{
Graphics<char>* sc; // 声明一个类模板指针,不需要实例化
func(*sc); // 需要实例化,传递给函数func的是一个Graphics对象
auto iobj = sizeof(Graphics<std::string>); // 需要实例化,因为sizeof会计算Graphics对象的大小,
// 为了计算大小,编译器必须根据类模板定义产生该类型。
return 0;
}
template <typename T>
class Graphics {
public:
Graphics() {}
// 成员函数定义在类模板的定义中
void print() {}
// 类中的虚函数不能用类型参数模板
// template
// virtual void func(U value) {
//
// }
private:
T m_value;
};
// 成员函数定义在类模板定义之外
template <typename T>
void Graphics<T>::print()
{
}
#include
// 普通类
class MyTest {
public:
// 成员函数模板
template <typename U>
void func(U val)
{
std::cout << "type=" << typeid(val).name() << " value:" << val << std::endl;
}
};
int main()
{
MyTest test;
test.func(100); // 普通类的成员函数模板:自动类型推导为int
test.func(10.0);// 普通类的成员函数模板:自动类型推导为double
return 0;
}
// 输出
// type=i value:100
// type=d value:10
#include
// 类模板
template <typename T>
class MyTest {
public:
MyTest(T val) : m_val(val) {}
// 普通成员函数
void print()
{
std::cout << "print() type=" << typeid(m_val).name() << " m_val:" << m_val << std::endl;
}
// 成员函数模板
template <typename U>
void func(U val)
{
std::cout << "template type=" << typeid(val).name() << " value:" << val << std::endl;
}
private:
T m_val;
};
int main()
{
MyTest<int> test(100); // 类模板实例化,显示指定类型T-> int
test.print();
test.func(10.0); // 类模板的成员函数模板,自动推导出U-> double
MyTest<double> test1(100.0); // 类模板实例化,显示指定类型T-> double
test1.print();
test1.func(10); // 类模板的成员函数模板,自动推导出U-> int
return 0;
}
// 输出
// print() type=i m_val:100
// template type=d value:10
// print() type=d m_val:100
// template type=i value:10
template <typename T>
class MyTest {
public:
// 构造函数模板
template <typename U>
MyTest(U value)
{
std::cout << "类模板泛化" << std::endl;
}
// 拷贝构造函数模板
template <typename T1>
MyTest(const MyTest<T1>& other)
{
std::cout << "拷贝构造函数模板" << std::endl;
}
// 拷贝赋值运算符模板
template <typename T2>
MyTest<T> & operator=(const MyTest<T2>& other)
{
std::cout << "拷贝赋值运算符模板" << std::endl;
}
// 成员函数模板
template <typename V>
void func(V param)
{
std::cout << "func param" << param << std::endl;
}
T m_value1;
static int m_static_value; // 静态成员变量
};
类模板的特化分为全特化与偏特化两种方式
全特化:对于全特化,类的所有参数都与模板类的所有参数一一对应
template <typename T, typename U>
struct MyTest
{
MyTest()
{
std::cout << "类模板泛化" << std::endl;
}
void func()
{
std::cout << "func函数泛化" << std::endl;
}
static int m_value;// 静态成员变量
};
// 普通成员函数全特化
template <>
void MyTest<int, double>::func()
{
std::cout << "func全特化" << std::endl;
}
template<typename T, typename U>
int MyTest<T, U>::m_value = 10;
// 静态成员函数全特化
template<typename T, typename U>
int MyTest<int, double>::m_value = 10;
偏特化:偏特化位于全特化和模板类之间,只对模板类的部分参数进行显示声明。类模板的偏特化主要有以下两个方面:一个是类模板参数变量的偏特化;另外一个是类模板参数范围上的偏特化;
// 模板类
template <typename T1, typename T2>
class Base {
public:
void func(T1& a, T2& b)
{
std::cout << "模板类: a = " << a << " b = " << b << std::endl;
}
};
// 全特化
// T1->int, T2-> double
template <>
class Base<int, double> {
public:
void func(int& a, double& b)
{
std::cout << "全特化类: a = " << a << " b = " << b << std::endl;
}
};
// 偏特化
// T1->默认为模板参数,T2-> double
template <typename T>
class Base<T, double> {
public:
void func(T& a, double& b)
{
std::cout << "偏特化类: a = " << a << " b = " << b << std::endl;
}
};
全特化类与偏特化类优先级:全特化 > 偏特化 > 模板类
#include
template <typename T1>
class Outter {
public:
Outter()
{
std::cout << "General Outter.\n";
}
template <typename T2>
class Inner {
public:
Inner()
{
std::cout << "General Inner.\n";
}
};
};
// 嵌套特化
template <> // 模板类的模板参数:Outter 特例化
template <typename T> // 模板类的模板成员类的模板参数:Inner 保持原样
class Outter<int>::Inner {
public:
Inner()
{
std::cout << "Specialized Inner.\n";
}
};
int main(int argc, char **argv)
{
Outter<int>::Inner<int> a;
Outter<double>::Inner<int> b;
return 0;
}
#include
// 类模板
template <typename T>
class A {
private:
T m_value;
friend class B;
};
// 普通类
class B {
public:
void func()
{
A<int> a;
a.m_value = 10;
std::cout << a.m_value << std::endl;
}
};
int main(int argc, char** argv)
{
B b;
b.func();
return 0;
}
#include
template <typename U>
class B;
// 类模板
template <typename T>
class A {
private:
T m_value;
friend class B<double>; // 类模板B的特化
};
template <typename U>
class B {
public:
void func()
{
A<double> a; //
a.m_value = 10;
std::cout << a.m_value << std::endl;
}
};
int main(int argc, char** argv)
{
B<double> b; // 必须和A中friend指定的参数一致
b.func();
//---------------------------
// compile error
// B b1;
// b1.func();
/*
main.cpp: In instantiation of ‘void B::func() [with U = int]’:
main.cpp:31:12: required from here
main.cpp:20:11: error: ‘double A::m_value’ is private within this context
20 | a.m_value = 10;
| ~~^~~~~~~
main.cpp:10:7: note: declared private here
10 | T m_value;
| ^~~~~~~
main.cpp:21:24: error: ‘double A::m_value’ is private within this context
21 | std::cout << a.m_value << std::endl;
| ~~^~~~~~~
main.cpp:10:7: note: declared private here
10 | T m_value;
*/
return 0;
}
#include
template <typename U>
class B;
// 类模板
template <typename T>
class A {
private:
T m_value;
template <typename U>
friend class B;
};
template <typename U>
class B {
public:
void func()
{
A<double> a;
a.m_value = 10;
std::cout << a.m_value << std::endl;
}
};
int main(int argc, char** argv)
{
B<double> b;
b.func();
B<int> b1;
b1.func();
return 0;
}
class Derived : public Base {}
template
class Derived : public Base {}
template
class Derived : public Base {}