tuple
2014-02-25 14:04
375 查看
返回值的捆绑
pair
使用std::pair<>来定义函数的返回值类型(顾名思义,std::pair<>可以将两个值凑成一对),像这样:std::pair<int,int> DevideInts(int n,int d)
{
return std::pair<int,int>(n/d,n%d);
}
缺点
只能提供两个返回值的捆绑,如果现在需要返回三个int呢方法一:自己定义一个结构
定义class/struct,保存三个乃至更多值缺点:
随着不同函数的需要你可能需要定义各种不同的类似这样的结构方法二:Tuple(代替struct)
能够用来保存任意型别的任意多个变量的类/tuple<>目前能够支持多达10个模板参数
boost::tuple<int,int,int>
someFunc();
Tuple原理
目标:tuple中的数据成员的个数应该具有某种动态特性 [利用了某种递归的概念];
tuple 必须提供某种途径以获取它内部保存的数值[通过某种编译期的递归],注意:当你需要获取第N个数据时,你所提供的N必须是编译期可计算出的常量。
boost::tuple源码剖析
//请记住它,后面我们将一直围绕这个例子boost::tuple<int,long,bool>myTuple(10,10,true);
tuple的声明
所有模板参数都有缺省值null_type:template < class T0
= null_type, class T1 = null_type, class T2
= null_type,
class T3 = null_type, class T4
= null_type, class T5 = null_type,
class T6 = null_type, class T7
= null_type, class T8 = null_type,
class T9 = null_type> // null_type是个空类
class tuple; // 注意这个声明的所有模板参数都有缺省值null_type
boost::tuple的定义
tuple只是将参数转交给基类处理:template <class T0, class T1, class T2, class T3, class T4,
class T5, class T6, class T7, class T8, class T9>
class tuple :
public detail::map_tuple_to_cons<T0,
T1, T2,T3, T4,
T5, T6, T7, T8,T9>::type
{
// tuple的定义体十分简单,其中是若干构造函数(将参数转交给基类)和模板赋值操作符
…
}; // 为了凸显重点,以下先讲tuple的基类
tuple的基类:map_tuple_to_cons<>
例子:tuple<int,long,bool>myTuple(10,10,true);相当于:
tuple<int,long,bool,
null_type,null_type,null_type,null_type,
null_type,null_type,null_type
> myTuple(10,10,true);
T0,T1,...,T9分别是int,long,bool,null_type,.....null_type。
基类定义
step1:递归定义:template <class T0, class T1, class T2, class T3, class T4,
class T5, class T6, class T7, class T8, class T9>
struct map_tuple_to_cons
{
// cons<>是数据的容器,也是所有奥秘所在
typedef cons<
T0, //第一个参数T0被孤立出来
typename map_tuple_to_cons<//剩下的模板参数后跟一个null_type进入下一轮
T1, T2, T3, T4, T5,T6, T7, T8, T9, null_type
>::type
> type;
};
step2模板特化:终止某种递归式
template <> //这个特化版本是终止某种递归式的自包含定义的关键,后面你会明白
struct map_tuple_to_cons<null_type,null_type, null_type, null_type,
null_type,null_type, null_type, null_type,
null_type,null_type>
{
typedef null_type type;
};
例子分析
上面已经知道T0,T1,...,T9被推导为int,long,bool,null_type,...,null_type
tuple的基类:
detail::map_tuple_to_cons<T0,T1, T2, T3, T4, T5, T6, T7, T8, T9>::type
被推导为
map_tuple_to_cons<int,long,bool,null_type,...,null_type>::type
根据map_tuple_to_cons的定义,其实就是:
cons< int,
typename map_tuple_to_cons<long,bool,null_type,...,null_type>::type
>
其中的
typename map_tuple_to_cons<long,bool,null_type,...,null_type>::type被推导为
cons<long,typename map_tuple_to_cons<bool,null_type,...,null_type>::type>
基类的定义的形式被推导成【原来的基类map_tuple_to_cons<int,long,bool,null_type,...,null_type>::type
】:
cons<int,
cons<long,
typename map_tuple_to_cons<bool,null_type,...,null_type>::type
>
>
最终推导成递归嵌套的模式:
cons<int,
cons<long,
cons<bool,
typename map_tuple_to_cons<null_type,...,null_type>::type
>
>
>
map_tuple_to_cons<>准备了一个特化版本来终止递归
使用模板特化中的typedef将
typename map_tuple_to_cons<null_type,...,null_type>::type
推导为null_type,得到最终的形式:
cons<int,cons<long,cons<bool,null_type>
>>
// 这实际上只是为int,long,bool各分配一份空间
这就是tuple<int,long,bool>的基类.
类似的:
如果tuple的形式为tuple<int,long,bool,double>,则其基类为:
cons<int,cons<long,cons<bool,cons<double,null_type>>
> >。
用户提供的模板参数个数的变化(反映用户需要保存的数据的个数)导致cons<>容器的嵌套层数的变化,进而导致tuple的底层内存的分配量也作相应变化。
总结:
map_tuple_to_cons<>以一种递归的方式不断将它的第一个模板参数割裂出来,并使tuple的基类呈现像这样的形式:
cons<T0,cons<T1,cons<T2,cons<T3,... ... > >> >
这种递归当map_tuple_to_cons<>的模板参数都为null_type时才恰好停止,。
1, map_tuple_to_cons<>不断将第一个模板参数取出,并将剩余的参数在尾部添一个null_type再传递下去。
2, 当用户给出的模板参数全部被分离出来时,map_tuple_to_cons<>所接受的参数就全部都是null_type了,于是使用其特化版本,其中将内嵌型别type typedef为null_type。从而结束这场递归。
基类中容器cons<>的定义
template <class HT, class TT>struct cons {
typedef HT head_type; // 这是个用户提供的型别
typedef TT tail_type; // 这通常是个cons<>的具现体
// 以上两个typedef很重要,并非可有可无
typedef
typename detail::wrap_non_storeable_type<head_type>::type
stored_head_type;
stored_head_type head; // 这是其中第一个数据成员
tail_type tail; // 第二个数据成员
... // 其成员函数将在后面解释,此处先略去
};
// cons<>还有一个偏特化版本:
template <class HT>
struct cons<HT,null_type> {
typedef HT head_type;
typedef null_typetail_type;
typedef cons<HT,null_type> self_type;
typedef typename
detail::wrap_non_storeable_type<head_type>::typestored_head_type;
stored_head_type head;
// 注意,不像上面的主模板,这里没有tail成员
... // 成员函数将在后面解释
};
根据cons<>的定义显示它有两个数据成员:
stored_head_type head; // 这是其中第一个数据成员
tail_type tail; // 第二个数据成员
对于第一个数据成员的型别stored_head_type,它被typedef为:
detail::wrap_non_storeable_type<head_type>::type
// 而head_type又被typedef为HT
其实它只是用来侦测你是否使用了void型别和函数类型【使用二者时利用模板特化】。
现在回顾我们的示例代码:tuple<int,long,bool>
myTuple;tuple<int,long,bool>的基类为:
cons<int,cons<long,cons<bool,null_type>
> >
所以,最外层的cons<>的模板参数被推导为:
typename HT=int,typename TT= cons<long,cons<bool,null_type>
>
这样,tuple<int,long,bool>的基类cons<int,cons<long,cons<bool,null_type>>
>其实只拥有两个成员:
int head;
cons<long,cons<bool,null_type>
> tail; // 注意这又是一个cons<>对象
tail成员又是cons<>的一个对象,不同的是tail的型别不同了——具现化cons<>的模板参数不同。可想而知,tail内部包含两个成员:
long head;
cons<bool,null_type>
tail;
值得注意的是,第二个tail的型别匹配的是cons<>的偏特化版本,其中只有一个数据成员:
bool head;
整个基类的内存布局其实就是cons<>的三重嵌套。
三个head数据成员就是需要分配内存的主体。
嵌套的结构,这种布局正像一种玩具——开始是一个盒子,揭开盒子其内部又是个更小的盒子,再揭,还是盒子...
嵌套的重数可以由用户给出的模板参数个数来控制。
特别注意:如果重数为N重,则只有N个head占用内存
相关文章推荐
- 分词常见算法-----小整理
- hdu2444(二分匹配)
- 发现msdn里面的一个错误
- android UI进阶之用ViewPager实现欢迎引导页面
- 找出四位数中的所有吸血鬼数
- 【Leafletjs】4.L.Map 中文API
- 微博相关性分类算法
- QT控件之状态栏
- windows系统读写INI文件的API
- android UI进阶之实现listview的分页加载
- 跟随自己,让自己的灵魂做主
- MyISAM InnoDB 区别
- 工程师们,不要想一辈子靠技术混饭吃
- UI issue only occurs in IE
- android UI进阶之实现listview的下拉加载
- 设置网页自适应最大最小宽度,超过则隐藏
- try语句...
- Word2007文档结构图层级错乱的解决办法(尤其打开2003兼容版本时)
- TMM软件测试成熟度模型
- Choose a destination with a supported architecture in order to run on this device. 模拟器设备问题