CTTCG 25 Tuples
类型计算可以在编译期间完成,取值的部分仍然是运行时操作。在 libc++
中被实现成多继承+反序构造,在 libstdc++
中被实现成双继承+正序构造。
Base
将元素包裹在 Base
中再继承可以利用到 EBCO(可优化时继承元素,不可优化时将元素作为成员)。通过给 Base
类模板添加下标作为参数,可以区分类型相同的元素。
get
函数
按下标获取:无论是 parameter pack 继承还是递归继承,由于有编号的存在,每个元素被存储位置的对应类型都是可以区分的。将 *this
转换成基类的引用再调用对应的 get()
方法(这个是 Base
的 get()
方法,不是元组的),或者直接用基类名作为限定名调用对应方法就能实现 get
。
按类型获取:逐个比较类型,直到类型相符。然后得到对应位置的下标,调用“按下标获取”的 get
重载版本。如果被指定的类型出现了多次,则应该造成编译失败。
reverse(反转元组)
尽管可以像上一章实现 Typelist 一样频繁拼接,但 Typelist 的拼接是在编译期间完成的,而元组的拼接是运行时操作,会造成多次数据拷贝(而且越靠近中间的数据拷贝次数越多)。
比较好的做法是构造从 N-1 到 0 的整数序列(C++ 标准库有构造从 0 到 N-1 的增序列的模板,却没有提供反向的),然后用 get
函数和 fold expression 构造参数列表,再传给元组的构造函数以便构造。这个过程只需要拷贝一次数据。
unpack / expanding
std::apply
(C++17)可以将 std::tuple
解包传入函数。