C++新标准—— 可变参数模板实现递归继承(tuple 实现原理)
·
C++ Variadic Templates 应用在 STL 的方方面面,可变参数的函数模板、类模板的核心工作机制是参数包的展开。C++17 之前通过递归的形式展开参数包,递归过程就是:将 N个元素的参数包分离第一个出来,将剩余的 N-1 个元素作为第2包,按照第1包过程继续分离第2包的一个元素,剩下 N-2 个元素作为第3包继续分离……这样不断重复下去,结果就是分离出最后一个且剩下一个空包,整个包就完全展开了。为了实现分离包的第一个元素,通常将模板参数列表定义为1个模板参数+1个可变参数的形式,如下 tuple 的模板参数列表:
recursive_inherited.hpp 定义了 tuple:
#pragma once
namespace ns_yao {
// [0] 类模板前置声明
template<class... _Tys>class tuple;
// [1] 空参数包特化版本,最后应用于继承链的最顶层,就上边说到的参数包分离到最后剩一个
// 空包时让编译器使用
template<>class tuple<> {};
// [2] tuple 形式像继承了自己,其实不然因为它们的模板参数列表不一样。
// 当调用方实例化类模板时会提供模板参数列表和函数参数列表,并将模板参数包进行分离:第一个模板
// 参数指明子类元素类型,剩余模板参数构成父类的模板参数包。父类的参数包同样要展开去实例化类模板
// 这样就形参递归,最后形成下边代码片段所示的类继承关系。
template<class _Head, typename... _Others>
class tuple<_Head, _Others...> : private tuple<_Others...>
{
typedef tuple<_Others...> parent;
public:
tuple() {}
// [3] 构造函数参数包展开,因为创建 tuple 对象时所有实参类型和模板参数类型是一一对应的,
// 所以分离剩余的参数包传给父类构造函数
tuple(_Head v, _Others... tails) : parent(tails...), m_head(v) {}
public:
_Head head() { return m_head;}
parent &inheritance() {return *this;}
private:
_Head m_head;
};
} // ns_yao
my_tuple_test.cpp 对 tuple 模板进行测试,给出了head() 、inheritance() 函数调用的等效代码以及类继承关系,最后还给出对象的内存模型:
#include "recursive_inherited.hpp"
#include <bitset>
#include <string>
#include <iostream>
int main(int argc, char* argv[])
{
using std::endl;
// [4]
ns_yao::tuple<int, float, std::bitset<8>, std::string>
tuple_v(88, .999f, -4, "hello typle");
// [5]
std::cout << tuple_v.head() << endl
<< tuple_v.inheritance().head() << endl
<< tuple_v.inheritance().inheritance().head() << endl
<< tuple_v.inheritance().inheritance().inheritance().head() << endl;
return 0;
}
// 基类引用绑定到派生类对象
// [5] inheritance() 函数的本质就是将 this 绑定到父类型引用上,实现静态绑定
inline ns_yao::tuple<float, std::bitset<8UL>, std::string> &ns_yao::tuple<int, float, std::bitset<8UL>, std::string>::inheritance() //
inline ns_yao::tuple<std::bitset<8UL>, std::string> &ns_yao::tuple<float, std::bitset<8UL>, std::string>::inheritance() //
inline ns_yao::tuple<std::string> &ns_yao::tuple<std::bitset<8UL>, std::string>::inheritance() //
//[5] 非虚函数调用采用静态绑定(调用基类版本)
inline int ns_yao::tuple<int, float, std::bitset<8UL>, std::string>::head()
inline float ns_yao::tuple<float, std::bitset<8UL>, std::string>::head()
inline std::bitset<8UL> ns_yao::tuple<std::bitset<8UL>, std::string>::head()
inline std::string ns_yao::tuple<std::string>::head()
*/
[6] 继承关系:
+-----------------------------------------------------------+
| ns_yao::tuple<> |
+-----------------------------------------------------------+
/|\
|
+-----------------------------------------------------------+
| ns_yao::tuple<std::string> |
|-----------------------------------------------------------|
| std::string m_head; |
+-----------------------------------------------------------+
/|\
|
+-----------------------------------------------------------+
| ns_yao::tuple<std::bitset<8UL>, std::string> |
|-----------------------------------------------------------|
| std::bitset<8UL> m_head; |
+-----------------------------------------------------------+
/|\
|
+-----------------------------------------------------------+
| ns_yao::tuple<float, std::bitset<8UL>, std::string> |
|-----------------------------------------------------------|
| float m_head; |
+-----------------------------------------------------------+
/|\
|
+-----------------------------------------------------------+
| ns_yao::tuple<int, float, std::bitset<8>, std::string> |
|-----------------------------------------------------------|
| int m_head; |
+-----------------------------------------------------------+
[7] 内存布局:
+---------------------------+
| 88 |
|---------------------------|
| .999f |
|---------------------------|
| 0b11111100 |
|---------------------------| 0x30150 + sizeof(string)
| "hello typle" |
+---------------------------+ 0x30150(this)
以上就是 tuple 的核心机制,应该讲的比较细致,如有错误欢迎指正。
更多推荐

所有评论(0)