可变参数模板

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++ 模板技术

  1. 可变参数模板 → 支持任意个数参数(你原来的 resize)
  2. 普通函数模板 → 支持任意类型,但参数个数固定
  3. 类模板 → 让整个类支持任意数据类型

逐段完整解释

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) → int
  • add(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 句超级简单的话

  1. 可变参数模板:传多少个数字都行
  2. 普通函数模板:传什么类型都行,但数量固定
  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>

意思:

  1. DType必须手动指定的类型(int/float/double)
  2. 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 句就够)

  1. template<typename DType, typename ..._Args>
    → 1个类型 + 任意参数
  2. DType 不在()里 → 必须写 < >
  3. _Args 在()里 → 自动推导,不用写 < >
  4. 返回 DType → 根据你写的 决定指针类型*

相关推荐
t***5442 小时前
如何在现代C++中更有效地应用这些模式
java·开发语言·c++
_深海凉_2 小时前
LeetCode热题100-最小栈
java·数据结构·leetcode
不知名的忻2 小时前
Morris遍历(力扣第99题)
java·算法·leetcode·morris遍历
daidaidaiyu2 小时前
一文学习入门 ThingsBoard 开源物联网平台
java·mqtt·spring
状元岐2 小时前
C#反射从入门到精通
java·javascript·算法
亚历克斯神2 小时前
Elasticsearch 全文搜索实战:构建企业级搜索引擎
java·spring·微服务
亚历克斯神2 小时前
Spring Boot 与 Elasticsearch 8.0 集成
java·spring·微服务
_深海凉_3 小时前
LeetCode热题100-除了自身以外数组的乘积
数据结构·算法·leetcode
Victoria.a3 小时前
python基础语法
开发语言·python