详细的讲解请看 CppMore 里缪大佬的 这篇文章。
此处学习一下其中的使用 递归继承 技巧实现简易元组类这个例子。
直接 “Show me the code!”
#include <iostream>
/*
先明晰省略运算符的意思:
typename... T --> 把一堆类型折叠到 T 中
T ... --> 从 T 中展开之前折叠的变量
*/
// #1: 先是 Tuple 类
// 主模板
template <typename... Types>
class Tuple;
// 全特化:作为终止递归的条件
template <>
class Tuple<> {};
template <typename Head, typename... Tail> // 将传递进来的参数分为第 1 个(称之为 Head)和其余个(第 2~N 个,折叠在 Tail 里)
class Tuple<Head, Tail...> : public Tuple<Tail...> { // 递归继承(采用公有继承)
public:
Tuple() {}
Tuple(Head v, Tail... vtails) : Tuple<Tail...>(vtails...), head_(v) {}
// 用来返回 Tuple 类的内部成员 head_ 的值,也是这个 Tuple 的第一个值
Head &head() { return head_; }
protected:
// head_ : 第一个值的意思,比如作为 Tuple<int, float, char> t(5, 2.7, 'b') 其中的 5
Head head_;
};
// #2: 然后是 TupleAt 类
// 主模板
template <std::size_t I, typename... TList>
struct TupleAt;
// 暂称 Tuple<T, TList...> 叫做“当前元组”
// 设计 TupleAt 的目的是获取到指定索引(I)处的元素的类型(称之为ValueType)(不必获取到具体的值,这个任务交给 Tuple 类的 head() 方法解决)
// ValueType 是“尾随元组”(意思是当前元组把第一项元素去掉,剩余的元素构成的元组)的第一个元素的类型
// TupleType 是“尾随元组”这一整体类型(它是当前元组的父类,因为 Tuple<Head, Tail...> 公有继承了 Tuple<Tail...>)
template <std::size_t I, typename T, typename... TList>
struct TupleAt<I, Tuple<T, TList...>> {
using ValueType = typename TupleAt<I - 1, Tuple<TList...>>::ValueType;
using TupleType = typename TupleAt<I - 1, Tuple<TList...>>::TupleType;
};
// 作为终止递归的条件:I = 0
template <typename T, typename... TList>
struct TupleAt<0, Tuple<T, TList...>> {
using ValueType = T;
using TupleType = Tuple<T, TList...>;
};
// #3: 最后还剩个 TupleGet 函数模板
/* TupleGet<I>(tuple) 这个函数模板在使用的时候(比如 TupleGet<2>(t))直观上接受两个参数:
其一,是模板参数 std::size_t I,表示索引;
其二,是函数参数 Tuple<TList...>& tuple,表示目标元组
TList 是目标元组 tuple 的模板参数们
*/
template <std::size_t I, typename... TList>
typename TupleAt<I, Tuple<TList...>>::ValueType &
TupleGet(Tuple<TList...> &tuple) {
using BaseTupleType = typename TupleAt<I, Tuple<TList...>>::TupleType;
return static_cast<BaseTupleType &>(tuple).head(); // 把当前元组强制转换其类型为上一层元组(也就是当前元组的尾随元组),.head() 的结果就会变成尾随元组的 head_
}
int
main() {
Tuple<int, float, char> t(1, 2.7, 'b');
Tuple<int, Tuple<int, float, char>, double> t2(4, t, 4.7);
std::cout << TupleGet<2>(t) << std::endl;
std::cout << TupleGet<0>(t2) << std::endl;
std::cout << TupleGet<2>(t2) << std::endl;
std::cout << TupleGet<2>(TupleGet<1>(t2)) << std::endl; // 嵌套元组也能正常处理哦
return 0;
}
这个程序实现了一个极简元组类,可以把不同类型的元素绑定在一起,并按下表索引访问元素。