侯捷 C++ 课程学习笔记:变参模板(Variadic Templates)
·
一、变参模板简介
变参模板(Variadic Templates)是 C++11 引入的一项重要特性,允许模板函数或模板类接受可变数量的参数。变参模板通过模板参数包(Template Parameter Pack)和函数参数包(Function Parameter Pack)实现,极大地增强了模板编程的灵活性和表达能力。
二、变参模板的基本用法
1. 模板参数包
模板参数包允许模板函数或模板类接受可变数量的类型参数。语法如下:
template <typename... Types>
void print(const Types&... args);
typename... Types:表示可变数量的类型参数。const Types&... args:表示可变数量的函数参数。
2. 函数参数包
函数参数包允许函数接受可变数量的参数。语法如下:
void print(const T&... args);
const T&... args:表示可变数量的函数参数。
三、变参模板的递归调用
变参模板的一个重要应用是递归调用,通过递归调用处理可变数量的参数。以下是一个示例:
void print() {
// 基本情况:没有参数
}
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args) {
std::cout << firstArg << std::endl; // 打印第一个参数
print(args...); // 递归调用,处理剩余参数
}
print():基本情况,处理没有参数的情况。print(const T& firstArg, const Types&... args):递归情况,处理第一个参数并递归调用处理剩余参数。
四、变参模板的示例
1. 打印多个参数
#include <iostream>
void print() {
// 基本情况:没有参数
}
template <typename T, typename... Types>
void print(const T& firstArg, const Types&... args) {
std::cout << firstArg << std::endl; // 打印第一个参数
print(args...); // 递归调用,处理剩余参数
}
int main() {
print(7.5, "hello", std::bitset<16>(377), 42);
return 0;
}
- 输出:
7.5 hello 0000000010111101 42
2. 计算哈希值
#include <functional>
template <typename T>
inline void hash_combine(std::size_t& seed, const T& val) {
seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
template <typename T, typename... Types>
inline void hash_val(std::size_t& seed, const T& val, const Types&... args) {
hash_combine(seed, val);
hash_val(seed, args...);
}
template <typename... Types>
inline std::size_t hash_val(const Types&... args) {
std::size_t seed = 0;
hash_val(seed, args...);
return seed;
}
class CustomerHash {
public:
std::size_t operator()(const Customer& c) const {
return hash_val(c.fname, c.lname, c.no);
}
};
- 解释:
hash_combine:将单个值的哈希值与种子值结合。hash_val:递归地计算多个值的哈希值。CustomerHash:使用hash_val计算Customer对象的哈希值。
五、变参模板的高级应用
1. 递归继承
变参模板可以用于实现递归继承,例如 std::tuple 的实现:
template <typename... Values>
class tuple;
template <>
class tuple<> {};
template <typename Head, typename... Tail>
class tuple<Head, Tail...> : private tuple<Tail...> {
Head m_head;
public:
tuple() {}
tuple(Head v, Tail... vtail) : m_head(v), tuple<Tail...>(vtail...) {}
Head& head() { return m_head; }
tuple<Tail...>& tail() { return *this; }
};
- 解释:
tuple<Head, Tail...>:继承自tuple<Tail...>,实现递归继承。m_head:存储第一个元素。head():获取第一个元素。tail():获取剩余元素的tuple。
2. 元组操作
tuple<int, float, string> t(41, 6.3, "nico");
t.head(); // 获取 41
t.tail().head(); // 获取 6.3
t.tail().tail().head(); // 获取 "nico"
- 解释:
t.head():获取第一个元素。t.tail().head():获取第二个元素。t.tail().tail().head():获取第三个元素。
六、学习心得
通过学习,我对变参模板有了更深入的理解。变参模板通过模板参数包和函数参数包,实现了对可变数量参数的支持,极大地增强了模板编程的灵活性和表达能力。
在实际编程中,变参模板可以用于实现递归调用、哈希计算、元组操作等复杂功能,提高代码的可读性和可维护性。特别是在处理不确定数量的参数时,变参模板提供了一种简洁而强大的解决方案。
更多推荐
所有评论(0)