cpp
#include <iostream>
using namespace std;
// ====================== 你原来的代码(不变)======================
// 【真正干活的函数】:接收 维度数量 + 数组
void real_resize(int dims, const int sizes[]) {
cout << "总维度数:" << dims << endl;
cout << "各维度大小:";
for (int i = 0; i < dims; ++i) {
cout << sizes[i] << " ";
}
cout << endl;
}
// 【可变参数模板】:接收任意个数 int 参数
template<typename ... Args>
void resize(int first, Args... args) {
const int size_array[] = {first, args...};
int total_dims = 1 + sizeof...(args);
real_resize(total_dims, size_array);
}
// ====================== 1. 普通函数模板(固定个数参数)======================
template<typename T>
T add(T a, T b) {
return a + b;
}
// ====================== 2. 类模板 ======================
template<typename T>
class MyTensor {
private:
T data_;
public:
MyTensor(T data) : data_(data) {}
void show() {
cout << "MyTensor 存储的数据类型:" << typeid(T).name() << endl;
cout << "数据值:" << data_ << endl;
}
T get() {
return data_;
}
};
// ====================== main 测试 ======================
int main() {
// ========== 你原来的:可变参数模板测试 ==========
cout << "===== 可变参数模板 resize =====" << endl;
cout << "--- 测试 1 维 ---" << endl;
resize(5);
cout << "\n--- 测试 2 维 ---" << endl;
resize(3, 4);
cout << "\n--- 测试 3 维 ---" << endl;
resize(3, 4, 5);
cout << "\n--- 测试 4 维 ---" << endl;
resize(1, 2, 3, 4);
// ========== 普通函数模板测试 ==========
cout << "\n===== 普通函数模板 add =====" << endl;
cout << "add<int>(1, 2) = " << add(1, 2) << endl;
cout << "add<double>(1.5, 2.3) = " << add(1.5, 2.3) << endl;
// ========== 类模板测试 ==========
cout << "\n===== 类模板 MyTensor =====" << endl;
MyTensor<int> t1(100);
t1.show();
MyTensor<float> t2(3.14f);
t2.show();
MyTensor<const char*> t3("hello");
t3.show();
return 0;
}
整体一句话总结
这段代码一共演示了 3 种 C++ 模板技术:
- 可变参数模板 → 支持任意个数参数(你原来的 resize)
- 普通函数模板 → 支持任意类型,但参数个数固定
- 类模板 → 让整个类支持任意数据类型
逐段完整解释
1. 真正干活的函数:real_resize
cpp
void real_resize(int dims, const int sizes[]) {
cout << "总维度数:" << dims << endl;
cout << "各维度大小:";
for (int i = 0; i < dims; ++i) {
cout << sizes[i] << " ";
}
cout << endl;
}
作用 :
这是真正执行输出的函数,接收:
- 维度数量 dims
- 维度数组 sizes[]
它不关心参数怎么传进来,只负责打印。
2. 可变参数模板(你最开始看不懂的 resize)
cpp
template<typename ... Args>
void resize(int first, Args... args) {
const int size_array[] = {first, args...};
int total_dims = 1 + sizeof...(args);
real_resize(total_dims, size_array);
}
作用 :
接收 任意个数的 int 参数
resize(5)resize(3,4)resize(3,4,5)
都能调用!
解释关键点:
template<typename ... Args>→ 可变参数模板(支持任意个数)int first→ 第一个参数固定Args... args→ 剩下所有参数{first, args...}→ 把所有参数拼成数组sizeof...(args)→ 计算可变参数有多少个- 最后调用 real_resize 输出
3. 普通函数模板(add)
cpp
template<typename T>
T add(T a, T b) {
return a + b;
}
作用 :
支持任意类型(int / double / float) ,但参数个数固定为 2 个。
例子:
add(1,2)→ intadd(1.5, 2.3)→ double
它只管类型通用,不管参数数量。
4. 类模板(MyTensor)
cpp
template<typename T>
class MyTensor {
private:
T data_;
public:
MyTensor(T data) : data_(data) {}
void show() {
cout << "数据类型:" << typeid(T).name() << endl;
cout << "数据值:" << data_ << endl;
}
};
作用 :
让整个类 可以存储任意类型的数据(int、float、字符串等)。
使用:
cpp
MyTensor<int> t1(100); // 存 int
MyTensor<float> t2(3.14f); // 存 float
MyTensor<const char*> t3("hello"); // 存字符串
类模板 = 给整个类开"通用类型"。
main 函数里都干了什么?
① 测试可变参数模板(任意个数参数)
cpp
resize(5);
resize(3,4);
resize(3,4,5);
resize(1,2,3,4);
输出维度数量 + 维度数组。
② 测试普通函数模板(任意类型,固定2个参数)
cpp
add(1,2);
add(1.5, 2.3);
③ 测试类模板(一个类存任意类型)
cpp
MyTensor<int> t1(100);
MyTensor<float> t2(3.14f);
MyTensor<const char*> t3("hello");
t1.show();
t2.show();
t3.show();
最重要的一张对比表(你一定要记住)
| 模板类型 | 写法 | 能力 | 用途 |
|---|---|---|---|
| 可变参数模板 | ... Args |
任意个数参数 | resize、shape、维度 |
| 普通函数模板 | <typename T> |
任意类型,固定个数 | add、max、min |
| 类模板 | template <typename T> class |
整个类通用类型 | Tensor、Vector |
你现在彻底懂了吗?
我可以再给你总结成 3 句超级简单的话:
- 可变参数模板:传多少个数字都行
- 普通函数模板:传什么类型都行,但数量固定
- 类模板:一个类能存 int、float、字符串等各种类型
cpp
#include <iostream>
template<typename DType, typename ... _Args>
inline DType* cpu(int n, _Args&&... dims)
{
// 用第一个模板参数 DType 决定数据类型
std::cout << "数据类型尺寸: " << sizeof(DType) << "\n";
std::cout << "batch = " << n << "\n";
std::cout << "维度参数:";
(std::cout << dims << " ", ...);
std::cout << "\n";
// 模拟分配 DType 类型内存
static char buf[1024];
return reinterpret_cast<DType*>(buf);
}
int main()
{
// int 类型指针,后续传多个维度
int* p1 = cpu<int>(2, 512, 256);
// float 类型指针
float*p2 = cpu<float>(4, 128, 128, 3);
return 0;
}
这是工程里最标准、最常用 的模板写法:
【1个固定类型 + 可变参数】
你现在看到的就是:
模板函数 = 显式指定类型 + 任意个数参数
我拆开讲,保证你彻底通透👇
1. 模板声明(最关键)
cpp
template<typename DType, typename ... _Args>
意思:
- DType :必须手动指定的类型(int/float/double)
- typename ... _Args :后面可以跟任意个数的参数(维度)
规则:
- DType 不在函数()里出现 → 必须写 < >
- _Args 是函数()里的参数 → 自动推导,不用写 < >
2. 函数定义
cpp
inline DType* cpu(int n, _Args&&... dims)
参数解释:
- int n:第一个参数(batch)
- _Args&&... dims :任意个数、任意类型的参数
返回值:
- DType* → 返回你指定类型的指针(int* / float*)
3. 调用方式(你最关心的地方)
cpp
int* p1 = cpu<int>(2, 512, 256);
float* p2 = cpu<float>(4, 128, 128, 3);
这里发生了什么?
cpu(2, 512, 256)
<int>→ 传给 DType(2,512,256)→ 传给n, dims...
cpu(4,128,128,3)
<float>→ 传给 DType(4,128,128,3)→ 传给n, dims...
4. 为什么必须带 < >?
因为 DType 只在模板里,不在函数参数里:
cpp
template<typename DType, ...>
DType* cpu(int n, ...)
编译器看不到 DType 在哪里 ,所以必须你手动写 /
5. 为什么后面不用写 < >?
因为 _Args 是从函数参数自动推导的:
cpp
cpu<int>(2, 512, 256);
- 2 → int
- 512 → int
- 256 → int
编译器自动推导出:
_Args = int, int
6. 这个写法在深度学习框架里 = 创建张量
cpp
Tensor<float>(2, 3, 64, 64)
和你这个:
cpp
cpu<float>(2, 3, 64, 64)
完全一样!
作用:
- :数据类型
- (2,3,64,64):形状 NCHW
7. 最终总结(你记这 4 句就够)
- template<typename DType, typename ..._Args>
→ 1个类型 + 任意参数 - DType 不在()里 → 必须写 < >
- _Args 在()里 → 自动推导,不用写 < >
- 返回 DType → 根据你写的 决定指针类型*