CTTCG 25 Tuples

类型计算可以在编译期间完成,取值的部分仍然是运行时操作。在 libc++ 中被实现成多继承+反序构造,在 libstdc++ 中被实现成双继承+正序构造。

Base

将元素包裹在 Base 中再继承可以利用到 EBCO(可优化时继承元素,不可优化时将元素作为成员)。通过给 Base 类模板添加下标作为参数,可以区分类型相同的元素。

get 函数

按下标获取:无论是 parameter pack 继承还是递归继承,由于有编号的存在,每个元素被存储位置的对应类型都是可以区分的。将 *this 转换成基类的引用再调用对应的 get() 方法(这个是 Baseget() 方法,不是元组的),或者直接用基类名作为限定名调用对应方法就能实现 get

按类型获取:逐个比较类型,直到类型相符。然后得到对应位置的下标,调用“按下标获取”的 get 重载版本。如果被指定的类型出现了多次,则应该造成编译失败。

reverse(反转元组)

尽管可以像上一章实现 Typelist 一样频繁拼接,但 Typelist 的拼接是在编译期间完成的,而元组的拼接是运行时操作,会造成多次数据拷贝(而且越靠近中间的数据拷贝次数越多)。

比较好的做法是构造从 N-1 到 0 的整数序列(C++ 标准库有构造从 0 到 N-1 的增序列的模板,却没有提供反向的),然后用 get 函数和 fold expression 构造参数列表,再传给元组的构造函数以便构造。这个过程只需要拷贝一次数据。

unpack / expanding

std::apply (C++17)可以将 std::tuple 解包传入函数。