要求
someTuple.get<N>(); // get是模板函数
要求:N必须得是编译期可计算的常量
为什么你不能试图用变量作“下标”来获取tuple中的变量?
someTuple.get(N); // N为变量-->错误
原因就在于get函数的返回值用户可以将不同形式的变量保存在tuple中,但是get函数是不能在运行期决定它的返回值的,返回值必须在编译期就决议出来。
tuple<int,long,bool>MyTuple;中有三个变量。
如果你写MyTuple.get<0>()则该get的具现化版本的返回值将被推导为int。
如果你写MyTuple.get<1>()则这个get的具现化版本返回值将被推导为long。get的返回值由其模板参数决定,而所有这些都在编译期。
get模板函数是怎样由它的模板参数(一个编译期整型数)来推导出其返回值的?
下面是cons<>成员get函数的源代码:
template <int N>
typename access_traits< //access_traits<>上面已经讲过
typename element<N, cons<HT,TT> >::type // element<>就是那个关键的traits
>::non_const_type// 注意这个复杂的返回类型
get() {
return boost::tuples::get<N>(*this); //转向全局的get<>函数
}
注:cons<>成员get函数内部调用 boost::tuples::get<N>(*this); //转向全局的get<>函数
请回顾我们的例子。假设我们现在写:
MyTuple.get<2>();
最外层cons<>的HT=int,TT=cons<long,cons<bool,null_type>>;
而调用的get正是最外层的。所以element<N,cons<HT,TT>>::type被推导为:
element<2,cons<int,cons<long,cons<bool,null_type>> > >::type
element<>的定义:递归定义+模板特化结束
emplate<int N, class T> // 这个int N会递减,以呈现递归的形式
struct element
{
private:
typedef typename T::tail_type Next;
// 在cons<>内部tail_type被typedef为TT,请回顾上面cons<>的代码
public: //cons<>内部有两个关键的typedef:head_type、tail_type
typedef typename element<N-1, Next>::type type; //递归
};
template<class T>
struct element<0,T> //递归至N=0时,山穷水尽
{
typedef typename T::head_type type; // 山穷水尽时直接将head_type定义为type
};
推导过程:
1, element<2,cons<int,cons<long,cons<bool,null_type> >> >::type
2, element<1,cons<long,cons<bool,null_type>> >::type;
3, element<0,cons<bool,null_type>>::type这下编译器得采用element<>的偏特化版本了(因为第一个模板参数为0)。
根据偏特化版本的定义(其中对type的typedef为:typedef typename T::head_type type;)你可以看出这实际就是:bool!
类似的:N=1时
typename element<1,cons<int,cons<long,cons<bool,null_type>> > >::type
ð typename element<0,cons<long,cons<bool,null_type>> >::type
第二行编译器会决定采用element<>的偏特化版本,从而这就是long!
get的比喻:
有一排人,第一个人手里拿着一块记数牌和一个盒子(记数牌上的数字表示模板参数N,盒子当然是cons<>数据容器)。
比如说,你告诉第一个人你像要那个盒子里的4号(第五个)元素(它深藏在第5重盒子里),他于是将记数牌上写上4,然后再减去一,并将盒子打开一层,将里面的小盒子(t.tail,也是个cons<>容器)和记数牌一并传给第二个人;
第二个人将记数牌上的3减去一,然后再剥去一层盒子,将里面的盒子以及记数牌(现在是2了)传给下一个人;
下一个人做同样的工作,直到第5个人(get_class<0>)发现记数牌上为0,那么他打开盒子,将里面的head元素传给第四个,后者再传给第三个...,一直传至你手里。
为了提高效率,get函数是inline的。
length<>来获得tuple的长度(即所含元素个数)
template<class T>
struct length {
staticconst int value = 1 + length<typename T::tail_type>::value; //递归
};
template<>
struct length<null_type>{
static const int value = 0;
};
用法
tuple<int,long,bool>MyTuple=make_tuple(10,10,true);
intival=10; long lval=10; bool bval=true;
tuple<int&,long&,bool&>MyTuple=tie(ival,lval,bval);
... // 这里,你修改MyTuple里的数据会直接影响到ival,lval,bval;
tuple<int&,string&>s(1,”345”);
访问:intj=std::get<0>(s);
std::tie(1, "aa", 2);
类型实际是:
std::tuple<int&,string&, int&>