Templates
Two reasons:
- function overwrite
- function default arguements(从右往左给默认才行)
alt text
函数模板:Function Template
类型Ambiguity
匹配顺序:
可匹配的普通的实例函数 > 模板函数 > 不匹配的普通函数能否实例转换
类模板
stack
queue
list
vector
都是类模板,后面<int>
就是对T的类型的指定实例化- 也可以同时使用多个templates类型
- templates也可以嵌套
- 同时模板的参数表里面可以不止有一个参数,也可以有其他实例参数
这个问题中
a
与b
根本就是两个不同的类,因为他们通过templates模板类的实例过程中的参数表不同,已经实例化为两个不同的类了,并不能直接转化
如果b
是<int,3>
那么a
与b
还可以用b=a
相互赋值拷贝,因为是同一个类
- Member Templates 成员模板
Eg:模板型的(成员)类型转化构造函数
- 类的继承中使用模板
- 递归继承模板(多态)
Morality
- 模板类的实现和声明,必须全部在.h的headfile文件里面
不要分开成header 和 cpp
- 如果.h中一个普通实例全局函数被include在两个.cpp文件中,并且两个.cpp被一起链接——肯定出现报错——
duplicate symbol linker error
因为两个.cpp文件中都include了这个头文件,这个函数在两个cpp文件中都出现,相当于这个全局函数一模一样出现了两份
这也是为什么,我们一开始会将.h只用于声明,而将函数的实现放在cpp文件中,这样就不会在多次多个include该模块的cpp链接的时候,被重复书写
- 但是模板或者inline函数被include两份他是不会报错的
如果你在 C++ 中使用
vector
这样的类模板构造对象时,没有指定模板参数的类型(例如 vector<int>
),而是直接写 vector a;
,那么会发生以下情况:1. 情况分析
C++98/03 标准
在 C++98/03 中,模板类的实例化必须明确指定模板参数类型。
因此,直接写
vector a;
是非法的,编译器会报错,因为它不知道 vector
应该使用哪种类型作为模板参数。C++11 及之后的标准
从 C++11 开始,标准引入了 模板类型推导 和 默认模板参数 的概念,但这些特性对
std::vector
并不适用。具体来说:
-
std::vector
没有默认的模板参数。
- 因此,
vector a;
仍然是非法的,编译器会报错。
2. 为什么会报错?
std::vector
是一个模板类,定义类似于:- 模板参数说明:
T
是存储元素的类型(如int
、double
等)。Allocator
是分配器类型,默认值是std::allocator<T>
。
- 当你写
vector a;
时,编译器无法推导出T
的类型,也没有提供默认值,因此会报错。
3. 正确的写法
你需要显式地指定模板参数类型,例如:
4. 如果你希望避免显式指定类型,可以使用 auto
或 std::initializer_list
使用 auto
从 C++11 开始,你可以使用
auto
结合类型推导:使用 std::initializer_list
C++11 引入了
initializer_list
,你可以通过列表初始化让编译器推导类型:但如果你不提供初始值,仍然需要显式指定类型:
5. 总结
vector a;
是非法的,因为编译器无法推导模板参数类型。
- 必须显式指定类型,例如:
std::vector<int> a;
。
- 如果希望通过自动推导类型,可以使用
auto
或initializer_list
(C++11 及之后)。
模板的特化
在 C++ 中,不一定需要先有一个通用模板函数才能写一个全特化的模板函数。
解释
模板函数的全特化是指为某个特定的模板参数提供专门的实现,而不是通用的实现。C++ 允许直接定义一个全特化的模板函数,而不需要先定义一个通用的模板函数。
1. 什么是模板函数的全特化?
模板函数全特化的形式如下:
在这里:
- 通用模板
func(T t)
是一个泛型函数,适用于所有类型 T
。
- 全特化模板 func<int>(int t)
是针对 int
类型的特化版本。2. 是否需要通用模板函数?
情况 1:先有通用模板函数
如果你先定义了一个通用模板函数,然后再为某些特定类型提供全特化版本,这是最常见的做法。例如:
情况 2:直接定义全特化模板函数
C++ 允许你直接定义一个全特化的模板函数,而不需要通用模板函数。例如:
在这种情况下:
- 只有
func<int>
被定义,其他类型的 func
不存在。
- 如果你尝试调用 func
的其他类型(如 double
),会导致编译错误。3. 注意事项
全特化 vs 偏特化
- 全特化:为某个具体类型(如
int
)提供特定实现。
- 偏特化:为一类特定类型(如
std::vector<T>
)提供特定实现。偏特化仅适用于类模板,函数模板不支持偏特化。
函数模板的全特化必须显式声明
函数模板的全特化必须显式地写出模板参数,例如:
而不能省略模板参数:
没有通用模板时的限制
如果没有通用模板函数,直接定义全特化版本,那么只有这个全特化版本存在,无法处理其他类型。例如:
此时
func<int>(int t)
或其他类型的调用都会报错。4. 总结
- 不需要先有通用模板函数,就可以直接定义全特化模板函数。
- 如果没有通用模板函数,则只有全特化的模板函数存在,其他类型的调用会报错。
- 通常情况下,先定义一个通用模板函数,再定义全特化版本,是更常见的做法,因为它提供了更大的灵活性。