<think>
我们被要求提供C++可变参数类模板的示例。根据引用[2]和引用[3],可变参数模板类允许我们定义接受任意数量模板参数的类。以下是一个简单的可变参数模板类的示例:
```cpp
#include <iostream>
// 可变参数模板类
template<typename... Args>
class Printer {
public:
Printer(Args... args) {
// 在构造时打印所有参数
printAll(args...);
}
private:
// 递归终止函数:当参数包中只剩下一个参数时调用
template<typename T>
void printAll(T value) {
std::cout << value << std::endl;
}
// 可变参数模板成员函数:处理多个参数
template<typename T, typename... Rest>
void printAll(T first, Rest... rest) {
std::cout << first << " ";
printAll(rest...); // 递归调用,处理剩余参数
}
};
int main() {
// 创建Printer对象,传入三个不同类型的参数
Printer<int, double, const char*> printer(1, 2.5, "hello");
return 0;
}
```
**代码解析**:
1. **可变参数模板类定义**:
```cpp
template<typename... Args>
class Printer
```
这里`Args`是一个模板参数包,表示可以接受任意数量和类型的模板参数。
2. **构造函数**:
```cpp
Printer(Args... args) {
printAll(args...);
}
```
构造函数接受与类模板参数包对应的参数包`args`(即参数的数量和类型与模板参数包`Args`一致)。在构造函数中,我们调用`printAll`函数打印所有参数。
3. **递归打印函数**:
- 递归展开函数(处理多个参数):
```cpp
template<typename T, typename... Rest>
void printAll(T first, Rest... rest) {
std::cout << first << " ";
printAll(rest...);
}
```
该函数将第一个参数打印出来,然后递归调用自身处理剩余的参数包`rest...`。
- 递归终止函数(处理最后一个参数):
```cpp
template<typename T>
void printAll(T value) {
std::cout << value << std::endl;
}
```
当参数包中只剩下一个参数时,调用此版本,打印该参数并换行。
4. **使用示例**:
```cpp
Printer<int, double, const char*> printer(1, 2.5, "hello");
```
实例化一个`Printer`类,模板参数指定为`int, double, const char*`,构造函数传入三个对应类型的值。运行后输出:
```
1 2.5 hello
```
**注意事项**:
- 可变参数模板的递归展开需要在编译时确定,因此递归终止函数必须存在,否则会导致编译错误。
- 参数包展开是递归进行的,可能会增加编译时间和生成代码的大小,但运行时效率很高(因为递归调用在编译时展开为顺序语句)[^3]。
---
### **另一个示例:计算参数包大小**
我们可以创建一个模板类来获取参数包中参数的数量:
```cpp
#include <iostream>
// 基础模板类
template<typename... Args>
struct Count;
// 模板特化:递归计数
template<typename First, typename... Rest>
struct Count<First, Rest...> {
static constexpr std::size_t value = Count<Rest...>::value + 1;
};
// 递归终止:当参数包为空时
template<>
struct Count<> {
static constexpr std::size_t value = 0;
};
int main() {
std::cout << "Number of types in <int, double, char>: "
<< Count<int, double, char>::value << std::endl; // 输出: 3
return 0;
}
```
**解析**:
- 使用模板特化和递归计算参数包中的类型数量。
- `Count<First, Rest...>`递归继承并累加计数,直到参数包为空(`Count<>`)时返回0。
---
### **相关问题**
1. 如何避免递归展开导致的编译代码膨胀?
2. 如何在可变参数模板中使用完美转发?
3. 可变参数模板在元编程中有哪些典型应用?
</think>
### C++可变参数类模板示例
以下是C++中可变参数类模板的典型实现示例,结合递归展开和编译时计算技术:
#### 1. 基础可变参数类模板
```cpp
#include <iostream>
// 递归终止条件(空参数包处理)
template <typename T>
class Tuple {
public:
Tuple(T val) : value(val) {}
void print() { std::cout << value; }
private:
T value;
};
// 可变参数模板类
template <typename T, typename... Args>
class Tuple<T, Args...> {
public:
Tuple(T first, Args... rest)
: first_(first), rest_(rest...) {}
void print() {
std::cout << first_ << " ";
rest_.print(); // 递归调用
}
private:
T first_;
Tuple<Args...> rest_; // 递归定义
};
int main() {
Tuple<int, double, std::string> t(42, 3.14, "Hello");
t.print(); // 输出: 42 3.14 Hello
return 0;
}
```
**核心机制**:
- 递归模板特化:通过主模板和偏特化实现参数包解包
- 编译时递归:参数包在编译期递归展开[^1]
- 类型安全:每个参数保持原始类型信息
#### 2. 参数计数器(编译时计算)
```cpp
#include <iostream>
template <typename... Types>
class TypeCounter {
public:
static constexpr std::size_t count() {
return sizeof...(Types); // 关键操作符
}
};
int main() {
std::cout << "Parameters: "
<< TypeCounter<int, double, char>::count() // 输出: 3
<< std::endl;
return 0;
}
```
使用`sizeof...`运算符直接获取参数包大小[^3]
#### 3. 完美转发可变参数
```cpp
#include <iostream>
#include <utility>
template <typename... Args>
class Processor {
public:
Processor(Args&&... args) {
process(std::forward<Args>(args)...);
}
private:
void process() {} // 终止递归
template <typename T, typename... Rest>
void process(T&& first, Rest&&... rest) {
std::cout << "Processing: " << first << std::endl;
process(std::forward<Rest>(rest)...); // 完美转发
}
};
int main() {
Processor<int, std::string> p(42, "Forward");
// 输出:
// Processing: 42
// Processing: Forward
return 0;
}
```
**关键技术**:
- `std::forward`保持值类别(左值/右值)
- 折叠表达式(C++17):简化递归展开[^2]
#### 4. 元组实现(标准库风格)
```cpp
template <typename... Ts>
class Tuple;
template <>
class Tuple<> {}; // 空元组特化
template <typename T, typename... Ts>
class Tuple<T, Ts...> : private Tuple<Ts...> {
public:
Tuple(T first, Ts... rest)
: Tuple<Ts...>(rest...), value(first) {}
T head() { return value; }
Tuple<Ts...> tail() { return *this; }
private:
T value;
};
// 使用示例
Tuple<int, double, char> t(1, 2.5, 'a');
std::cout << t.head(); // 1
```
---
### 关键特性总结
1. **参数包操作**:
- `typename...` 声明参数包
- `Args...` 展开参数包
- `sizeof...(Args)` 获取参数数量
2. **递归模式**:
- 主模板处理边界条件
- 偏特化实现递归展开
3. **编译时计算**:
- 递归实例化在编译期完成
- 零运行时开销(模板元编程)[^1]
**应用场景**:
- 元组(`std::tuple`)、变参函数对象(`std::function`)
- 类型安全的格式化输出
- 编译期数据结构构建
- 序列化框架的基础组件
---