VS2013 tuple 源码分析

tuple这玩意实现方法就是递归方式展开函数包的完美示例。相关文章可以查看<深入应用C++11>3.2.1.1章节。

tuple的实现思想可以查看侯捷老师视频:https://www.bilibili.com/video/BV1p4411v7Dh?p=20

假如我们现在有如下源码:

tuple<int, double, char*> my_tuple = make_tuple(1,2.2,"love")

好吧来看 VS2013实现源码:

	// CLASS tuple这里是前置声明
template<class... _Types>
	class tuple;

template<>//这里是特化版本,为了中止继承
	class tuple<>
	{	
        //这里没有成员函数,什么都不存
        }

//这里是真正普通模板类
template<class _This,//_This 就对应我们上面例子中的1对应的 int 类型
	class... _Rest> //_Rest 就对应 double 和 char* 组成的一包
	class tuple<_This, _Rest...>
		: private tuple<_Rest...>//这里继承于自己,当然也不是自己,因为模板参数不一样
	{
public:
	typedef _This _This_type;
	typedef tuple<_This, _Rest...> _Myt;
	typedef tuple<_Rest...> _Mybase;
	static const size_t _Mysize = 1 + sizeof...(_Rest);

	_Tuple_val<_This> _Myfirst;	// the stored element//这里存放第一个int类型的1
       }

 

	// CLASS tuple_element
template<size_t _Index,	class _Tuple>
	struct tuple_element;

template<class _This,class... _Rest>
	struct tuple_element<0, tuple<_This, _Rest...> >
	{	// select first element
	typedef _This type;
	typedef typename add_lvalue_reference<const _This>::type _Ctype;
	typedef typename add_lvalue_reference<_This>::type _Rtype;
	typedef typename add_rvalue_reference<_This>::type _RRtype;
	typedef tuple<_This, _Rest...> _Ttype;
	};

template<size_t _Index,	class _This,class... _Rest>
	struct tuple_element<_Index, tuple<_This, _Rest...> >//这里tuple也会拆包,直到_Index为0,此时我们想要取的值,为此类型tuple的成员变量。
		: public tuple_element<_Index - 1, tuple<_Rest...> >//这里_Index 会递减,直到第一个模板参数为0
	{	// recursive tuple_element definition
	};
	
// FUNCTION get
template<size_t _Index,	class... _Types> inline//这个_Types是 get函数的参数tuple的模板参数类型
	typename tuple_element<_Index, tuple<_Types...> >::_Rtype//这里会根据_Types进行递减
		get(tuple<_Types...>& _Tuple)//根据这里的_Tuple能够推导出tuple的一包参数_Types
	{	// get reference to _Index element of tuple
	typedef typename tuple_element<_Index, tuple<_Types...> >::_Ttype _Ttype;
	return (((_Ttype&)_Tuple)._Myfirst._Val);//_Ttype是存着我们那个值的基类,强转即可
	}

编译器编程可以运行期编程难多了。如果是运行期,可能会这样:get(0),而编译器是这样get<0>()。妙哉妙哉。

	// CLASS _Ignore
class _Ignore
	{	// class that ignores assignments
public:
	_Ignore()
		{	// construct
		}

	template<class _Ty>//任何类型变量都可以赋值给此类型变量
		void operator=(const _Ty&) const
		{	// do nothing
		}
	};

const _Ignore ignore;
// FUNCTION tie
template<class... _Types> inline
	tuple<_Types&...>
		tie(_Types&... _Args) _NOEXCEPT
	{	// make tuple from elements
	typedef tuple<_Types&...> _Ttype;
	return (_Ttype(_Args...));//这里很简单就是把原tuple包赋值给现tuple包。
	}

再讲讲tuple_cat实现方式:

	std::tuple<int, double> my_tuple1(1, 2.2);
	std::tuple<char*> my_tuple2("beijing");
        std::tuple_cat(my_tuple1, my_tuple2);
template<class... _Tuples> inline
	typename _Tuple_cat1<_Tuples...>::type
		tuple_cat(_Tuples&&... _Tpls)
	{	// concatenate tuples
	typedef _Tuple_cat1<_Tuples...> _Cat1;
	return (_Tuple_cat<typename _Cat1::type>(
		typename _Cat1::_Kx_arg_idx(), typename _Cat1::_Ix_arg_idx(),
		_STD forward_as_tuple(_STD forward<_Tuples>(_Tpls)...)));
	}
template<class _Ret,
	size_t... _Kx,
	size_t... _Ix,
	class _Ty> inline
	_Ret _Tuple_cat(_Arg_idx<_Kx...>, _Arg_idx<_Ix...>, _Ty&& _Arg)
	{	// concatenate tuples
		cout << typeid(_Arg_idx<_Kx...>).name() << endl;//我自己添加的打印
		cout << typeid(_Arg_idx<_Ix...>).name() << endl;

		cout << typeid(_Ty).name() << endl;
	return (_Ret(_STD get<_Kx>(_STD get<_Ix>(_STD forward<_Ty>(_Arg)))...));
	}

打印结果如下: 

struct std::_Arg_idx<0,1,0>//上面这个和下面_Arg_idx这个上下对应关系
struct std::_Arg_idx<0,0,1>
class std::tuple<class std::tuple<int,double> &,class std::tuple<char *> &>

先取内层get _Arg_idx的最后一个模板参数即为1,即get<1>(my_tuple1)就得到my_tuple2,然后再调用外层get的_Arg_idx的最后一个模板参数0,即get<0>(my_tuple2)就得到了“beijing",这样依次轮询三次后,得到一个模板参数包{1,2.2,"beijing"},_Ret是返回类型tuple<int,double,char*>。用_Ret强转参数包得到了最终得tuple。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值