注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

一路

To find the final symmetry & beauty

 
 
 

日志

 
 
 
 

SGI STL 源码阅读笔记6 类型萃取前奏[原创]  

2011-02-15 23:20:35|  分类: c++学习笔记 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

    在应用中我们可能有这样的需求,就是知道一个容器中装的是什么类型,或是迭代器指向的东西是什么类型。这种类型都被称为关联类型,关联类型不一定是一种类型,比如一个容器内装的是类型T,那么类型T的指指T*,指针的差是什么类型T*-U*,(T和U为向一类型),常量指针的类型,const T*,如此等等,但是我们的需求不是已知容器后再得到其内装元素的类型,我们是想写一个模版函数,参数是装着任意类型的任意容器,这个工作看似简单其实并非如此简单。

    我把我知道的方式总结如下:

//filename: get_associated_type.cpp

//written by saturnman

#include<iostream>

#include<vector>

using namespace std;

template<typename T>

class Container

{

    public:

        typedef T value_type;

};

class A

{

    public:

    friend ostream& operator<<(ostream& out,A const& input)

    {

        cout<<"Class A"<<endl;

    }

};

//use c++0x newest feature 'var template parameter'

template<typename T1,template <typename T1,typename... Types>class TContainer>

T1 get_type1(TContainer<T1> const&)

{

    T1 t;

    cout<<t<<endl;

    return t;

}

//make internal typedef

template<typename T>

class Iterator

{

    public:

        typedef T value_type;

};

//use utility function

template<typename T1>

void get_type2(T1 t)

{

    get_type2_impl(t,t[0]);

}

template<typename T1,typename T2>

void get_type2_impl(T1,T2)

{

    T2 var;

    cout<<var<<endl;

}

//use internal type

template<typename T1>

void get_type3(T1 const&)

{

    typename T1::value_type var;

    cout<<var<<endl;

}

//use traits

template<typename _Iterator>

class Type_Traits

{

    public:

        typedef typename _Iterator::value_type value_type;

};

//partial specialization for primitive pointer

template<typename T>

class Type_Traits<T*>

{

    public:

        typedef T value_type;

};

//partial specialization for const primitive pointer

template<typename T>

class Type_Traits<const T*>

{

    public:

        typedef T value_type;

};

//partial specialization for void* make error occur

//if out client use this.

template<>

class Type_Traits<void*>

{

    public:

        typedef void value_type;

};

template<typename _Iterator>

void get_type4(_Iterator const&)

{

    typedef typename Type_Traits<_Iterator>::value_type value_type;

    value_type var;

    cout<<var<<endl;

}

int main()

{

    A a;

    Container<int> c1;

    Container<double> c2;

    Container<A> c3;

    vector<A> v1;

    v1.push_back(a);

    get_type1(c1);

    get_type1(c2);

    get_type1(c3);

    get_type1(v1);

    get_type2(v1);

    get_type3(v1);

    get_type3(c3);

    Iterator<A> i1;

    int* i2;

    double* i3;

    get_type4(i1);

    get_type4(i2);

    get_type4(i3);

    return 0;

}

 

所有的get_typex函数都是把关联类型取出并用此类型生成一个变量,之后输出。Get_type1是使用了依赖模版参数的模版参数,我用自己定义的Container生成了不内装不同类型的三个变量,c1,c2,c3,再用标准库中的vector生成了一个变量v1,这个函数都成功把类型取出。这个get_type1的模版变量TContainer依赖示模板T和其它不定个数的模板参数,这里哪果只设定依赖一个模板参数则vector的容器变量不能工作,原因是vector<A>类型的全称是vector<A,allocator<A> >,虽然vector的第二个函数有默认值,但是编译器并不处理这个默认值,它认为找不到匹配函数。只有使用不定模版函数才能把这个默认模版推导出来。不定模板参数是C++标准最新的特性,请使用最新的编译器编译它,例如VS2010或是GCC.4.5+ g++要打开0x支持选项,-std=c++0x。get_type2是使用一个工具函数,它使用一个容器本身的函数操作,这个操作能返回容器中的一个元素或是元素引用,之后调用两参数的模版工具函数把这个返回值类型推导出来加以例用。Get_type3使用了容器的内置类型定义,相当于嵌套类型。我们在函数中直接使用这人嵌套类型就可以了,十分方便。Get_type4使用了一个工具类,多了一层间接性,它把容器内置类型转为自己工具类的内置类型,之后函数直接调用这个工具类的内部类型。

    下面来分析一下上面的方法的特点,get_type1对于取出容器元素类型并不好用,但是它只能取出单一类型,如果一个容器有多个相关类型,那么就要写多个这种函数,而且语法奇怪。这种方式就比较麻烦,但是这个函数有一个特点比较好,它对容器或是输入类型没有什么特别的要求,这种函数可以用在简单的内部关联类型的获取应用上。Get_type2这个函数通用性是最差的,它只能获取一个类型外还要要求容器的指定的操作,十分不易使用,我把它列在这里只是为了凑齐这种技术的数量。Get_type3这种方式工作十分直接,发果我们让所有的容器都有这样的相同名称的内部定义就可以直接使用这种函数,为了统一接口我们可以让容器继承一个公共接口,但是对于定义容器这样的内置类型是好说了,发果对于迭代器呢。我们知道并非有的迭代器都是自定义类型,比如原生指针。原生指针并没有内部定义的嵌套类型,处理这种不足就要看get_type4了,它在其中加了一层间接性,我们利用类的偏特化对原生指针T*,const T*,甚至void*都做了特化处理,把它们做为traits的参数就不用担心没有内置类型定义了,而且在以后的日志中我会提到用这种traits技术可以达到简洁高效的目地,例用某些类型的本身特性的偏特化可以极大提高程序性能而不知泛型算法的通用性,理解traits技术是进入SGI STL源代码的大门。

Ref:

[1]. 侯捷,《STL源码剖析》

[2]. Working Draft, Standard for Programming Language C++

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3225.pdf

  评论这张
 
阅读(779)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017