Templates

Two reasons:
  • function overwrite
  • function default arguements(从右往左给默认才行)
notion image
alt text

函数模板:Function Template

类型Ambiguity
匹配顺序:
可匹配的普通的实例函数 > 模板函数 > 不匹配的普通函数能否实例转换
notion image
notion image

类模板

notion image
stack queue list vector 都是类模板,后面<int>就是对T的类型的指定实例化
  • 也可以同时使用多个templates类型
notion image
  • templates也可以嵌套
  • 同时模板的参数表里面可以不止有一个参数,也可以有其他实例参数
    • notion image
      notion image
notion image
这个问题中ab根本就是两个不同的类,因为他们通过templates模板类的实例过程中的参数表不同,已经实例化为两个不同的类了,并不能直接转化
如果b<int,3>那么ab还可以用b=a
相互赋值拷贝,因为是同一个类
  • Member Templates 成员模板
    • notion image
Eg:模板型的(成员)类型转化构造函数
notion image
notion image
  • 类的继承中使用模板
    • notion image
  • 递归继承模板(多态)
    • notion image

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 是存储元素的类型(如 intdouble 等)。
    • Allocator 是分配器类型,默认值是 std::allocator<T>
  • 当你写 vector a; 时,编译器无法推导出 T 的类型,也没有提供默认值,因此会报错。

3. 正确的写法

你需要显式地指定模板参数类型,例如:

4. 如果你希望避免显式指定类型,可以使用 autostd::initializer_list

使用 auto

从 C++11 开始,你可以使用 auto 结合类型推导:

使用 std::initializer_list

C++11 引入了 initializer_list,你可以通过列表初始化让编译器推导类型:
但如果你不提供初始值,仍然需要显式指定类型:

5. 总结

  • vector a; 是非法的,因为编译器无法推导模板参数类型。
  • 必须显式指定类型,例如:std::vector<int> a;
  • 如果希望通过自动推导类型,可以使用 autoinitializer_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. 总结

  • 不需要先有通用模板函数,就可以直接定义全特化模板函数。
  • 如果没有通用模板函数,则只有全特化的模板函数存在,其他类型的调用会报错。
  • 通常情况下,先定义一个通用模板函数,再定义全特化版本,是更常见的做法,因为它提供了更大的灵活性。
Loading...