`
rbd243tl
  • 浏览: 16653 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

Boost中应用的泛型编程技术

阅读更多

Boost中应用的泛型编程技术
2009年10月23日
  
何谓泛型编程泛型编程(Generic Programming)关注于产生通用的软件组件,让这些组件在不同的应用场合都能很容易地重用。在C++中,类模板和函数模板是进行泛型编程极为有效的机制。有了这两大利器,我们在实现泛型化的同时,并不需要付出效率的代价。
  作为泛型编程的一个简单例子,让我们看一下在C库中如何让memcpy()函数泛型化。一种实现方法可能是这样的:
  void* memcpy(void* region1, const void* region2, size_t n){    const char* first = (const char*)region2;    const char* last = ((const char*)region2) + n;    char* result = (char*)region1;    while (first != last)        *result++ = *first++;    return result;}   

  这个memcpy()函数已经在一定程度上进行了泛型化,采取的措施是使用void*,这样该函数就可以拷贝不同类型的数组。但如果我们想拷贝的数据不是放在数组里,而是由链表来存放呢?我们能不能扩展这个概念,让它可以拷贝任意的序列?看看memcpy()的函数体,这个函数对传入的序列有一个_最小需求_:它需要用某种形式的指针来遍历这个序列;访问指针正指向的元素;把元素写到目的地;比较指针以判断何时停止拷贝。C++标准库把这样的需求进行分组,称之为概念(concepts)。在这个例子中就有输入迭代器(对应于region1)和输出迭代器(对应于region2)这两个概念。
  如果我们把memcpy()用函数模板重写,使用输入迭代器和输出迭代器作为模板参数来描述对序列的需求,我们就可以写出一个具有较高重用性的copy()函数:
  template OutputIteratorcopy(InputIterator first, InputIterator last, OutputIterator result){    while (first != last)        *result++ = *first++;    return result;}   

  使用这个泛型的copy()函数,我们可以拷贝各种各样的序列,只要它满足了我们指定的需求。对外提供了迭代器的链表,比如std::list,也可以通过我们的copy()函数来拷贝:
  #include #include #include int main(){    const int N = 3;    std::vector region1(N);    std::list region2;        region2.push_back(1);    region2.push_back(0);    region2.push_back(3);        std::copy(region2.begin(), region2.end(), region1.begin());        for (int i = 0; i 看起来是这个样子:[b]
  template struct iterator_traits {    typedef ... iterator_category;    typedef ... value_type;    typedef ... difference_type;    typedef ... pointer;    typedef ... reference;};   

  该traits的value_type可以让泛型代码得知该迭代器所“指向”的是何种类型的数据;而iterator_category对迭代器的能力进行分类,针对不同类型的迭代器我们选择与之适应的最高效的算法。
  traits模板有一个很重要的特点:它们是非侵入的(non-intrusive)。我们可以为任何类型提供相关信息,不管它是内建的类型,还是第三方的库中提供的类型。为了给某一特定类型指定traits,一般采用部分特化或者全特化traits模板的方式。
  欲更深入的了解std::iterator_traits,可以参阅SGI提供的资料。std::numeric_limits也采用了traits技术,提供表示各内建数值类型取值范围的常量值。标记分派
  另外有一种技术经常与traits合用,那就是标记分派。它依据类型的属性,通过函数重载进行分派。一个很好的例子就是std::advance()函数。这个函数的功能是将一个迭代器递增n次,对于不同类型的迭代器可以有各自优化的实现方法。如果是随机访问迭代器(可以以任意的距离前后跳转),advance()函数可以用i+=n来实现,既简单又高效,只需要常量时间。而其它的迭代器必须一步一步地递增,需要线性的时间复杂度。如果是双向迭代器,n就可能为负值,因此必须判断对迭代器到底是增还是减。
  标记分派和traits类的联系很紧密。分派所依据的属性(在这个例子中是iterator_category)一般都是通过traits类来取得。主advance()函数从iterator_traits中获得对应于该iterator的iterator_category,然后调用重载过的advance_dispach()函数。编译器依据作为参数传给advance_dispach()的iterator_category,选择合适的重载版本。标记只是一个极其简单的类,它的唯一任务就是为标记分派或者其它类似技术传递必要的信息。
  namespace std {  struct input_iterator_tag { };  struct bidirectional_iterator_tag { };  struct random_access_iterator_tag { };  namespace detail {    template     void advance_dispatch(InputIterator& i, Distance n, input_iterator_tag) {      while (n--) ++i;    }    template     void advance_dispatch(BidirectionalIterator& i, Distance n,       bidirectional_iterator_tag) {      if (n >= 0)        while (n--) ++i;      else        while (n++) --i;    }    template     void advance_dispatch(RandomAccessIterator& i, Distance n,       random_access_iterator_tag) {      i += n;    }  }  template   void advance(InputIterator& i, Distance n) {    typename iterator_traits::iterator_category category;    detail::advance_dispatch(i, n, category);  }}   
适配器
  适配器是一种类模板,建立在其它类型之上,提供新的接口或者行为。标准库中就使用了适配器,比如std::reverse_iterator通过反转迭代器的递增/递减行为,适配了迭代器,还有std::stack,通过适配标准容器,提供一个简单的堆栈接口。
  在这里可以找到标准库中所用适配器的深入阐述。类型生成器
  类型生成器的工作是依据它的模板参数合成新的类型[注]。类型生成器产生的新类型一般作为生成器中嵌套的typedef出现。用类型生成器的主要目的是为了让复杂的类型表达式显得更简单些。比如boost::filter_iterator_generator:
  template struct filter_iterator_generator {    typedef iterator_adaptor,        Value,Reference,Pointer,Category,Distance> type;};   

  看起来可真够复杂的。但现在生成一个合适的filter iterator可就容易多了,只需要写:
  boost::filter_iterator_generator::type   

  就行了。对象生成器
  对象生成器是一种函数模板,依据其参数产生新的对象。可以把它想象成泛型化的构造函数。有些情况下,欲生成的对象的精确类型很难甚至根本无法表示出 来,这时对象生成器可就管用了。对象生成器的优点还在于它的返回值可以直接作为函数参数,而不像构造函数那样只有在定义变量时才会调用。Boost和标准 库中用到的对象生成器大多都加了个前缀make_,比如std::make_pair(const T&, const U&)。
  看看下面的例子:
  struct widget {  void tweak(int);};std::vector widget_ptrs;   

  通过把两个标准的对象生成器bind2nd和mem_fun合用,我们可以很轻松地tweak所有的widget:
  void tweak_all_widgets1(int arg){   for_each(widget_ptrs.begin(), widget_ptrs.end(),      bind2nd(std::mem_fun(&widget::tweak), arg));}   

  如果不用对象生成器,上面的函数可能就得这样来实现:
  void tweak_all_widgets2(int arg){   for_each(struct_ptrs.begin(), struct_ptrs.end(),      std::binder2nd >(          std::mem_fun1_t(&widget::tweak), arg));}   

  表达式越复杂,就越需要缩短这些冗长的类型说明,对象生成器的好处也就越能显现。策略类
  策略类就是用来传递行为的模板参数。标准库中的std::allocator就是策略类,把内存管理的行为应用到标准容器中。
  Andrei Alexandrescu在他的文章中对策略类进入了全面而深入的分析,他写道:
  “策略类精确地反映了设计时的抉择。他们要么从其它类中继承,要么包含在其它类中。策略类在同样的句法结构上提供了不同的策略。使用策略的类把它用到的每一个策略都作为模板参数,这样,用户就可以自由地选择需要使用的策略。
  策略类的强大在于它们能够自由地组合在一起。通过把策略类作为模板参数的办法来组合多种策略,代码量与使用的策略数只成线性关系。”
  Andrei认为策略类的强大源于其小粒度和正交性。Boost在迭代适配器库中的策略类运用可能淡化了这一卖点。在这个库中,所有已适配的迭代器的行为都放在一个策略类里面。其实,Boost并不是开先河者。std::char_traits就是一个策略类,它决定了std::basic_string的行为,尽管它的名字叫traits而不叫policy。
  注:因为C++缺少模板化的typedef,类型生成器可以作为其替代方案。
分享到:
评论

相关推荐

    Boost程序库完全开发指南.pdf

     它由C++标准委员会部分成员所设立的Boost社区开发并维护,使用了许多现代C++编程技术,内容涵盖字符串处理、正则表达式、容器与数据结构、并发编程、函数式编程、泛型编程、设计模式实现等许多领域,极大地丰富了...

    Boost程序库完全开发指南

    Boost由C++标准委员会部分成员所设立的Boost社区开发并维护,使用了许多现代C++编程技术,内容涵盖字符串处理、正则表达式、容器与数据结构、并发编程、函数式编程、泛型编程、设计模式实现等许多领域,极大地丰富了...

    Boost程序库完全开发指南:深入C++“准”标准库+.pdf

     它由C++标准委员会部分成员所设立的Boost社区开发并维护,使用了许多现代C++编程技术,内容涵盖字符串处理、正则表达式、容器与数据结构、并发编程、函数式编程、泛型编程、设计模式实现等许多领域,极大地丰富了...

    BOOST程序库完全开发指南:深入C++“准”标准库(第3版).罗剑锋(带详细书签)

    Boost由C++标准委员会部分成员所设立的Boost社区开发并维护,使用了许多现代C++编程技术,内容涵盖字符串处理、正则表达式、容器与数据结构、并发编程、函数式编程、泛型编程、设计模式实现等许多领域,极大地丰富...

    Boost程序库完全开发指南第3版

    , 它由C++标准委员会部分成员所设立的Boost社区开发并维护,使用了许多现代C++编程技术,内容涵盖字符串处理、正则表达式、容器与数据结构、并发编程、函数式编程、泛型编程、设计模式实现等许多领域,极大地丰富了...

    第二届C++技术大会(下)

    大规模软件开发 Large-Scale ... 泛型编程与设计 Generic Programming 网络与服务端开发 Network & Server-Side Development 多核与并发编程 Multicore Parallel Programming 工具与应用 Tools & Applications

    C++模板元编程(C++ 领域扛鼎之作,荣耀先生倾情翻译,名著名译) 原书名: C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond

    自从泛型编程被引入C++中以来,程序员们已经发现用于当程序被编译时对其进行操纵的无数“tricks template”,这些tricks有效地消除了横亘在程序和元编程之间的藩篱。尽管C++专家们对这种能力的兴奋已经波及整个C++...

    Beyond.the.C.plus.plus.Standard.Library.An.Introduction.to.Boost

    同时,Boost库内容广泛,包括数值计算、泛型编程、元编程、智能指针、类型转换等众多内容,所以可以从中选择自己感兴趣的部分,细细品味。 本书是市面上第一本全面深入介绍Boost的著作,因此对于那些勇于探索的C++...

    C++模板元编程中文扫描PDF 2/2

    自从泛型编程被引入C++中以来,程序员们已经发现用于当程序被编译时对其进行操纵的无数“tricks template”,这些tricks有效地消除了横亘在程序和元编程之间的藩篱。尽管C++专家们对这种能力的兴奋已经波及整个C++...

    第二届C++技术大会

    大规模软件开发 Large-Scale Software ...泛型编程与设计 Generic Programming 网络与服务端开发 Network & Server-Side Development 多核与并发编程 Multicore Parallel Programming 工具与应用 Tools & Applications

    [C#入门经典.第5版].中文.(Beginning.Visual.C#.2010).齐立波.

    最新版的《C#入门经典(第5版)》 全面讲解C# 2010基础知识,浓墨重彩地描述web和windows编程以及数据访问(数据库和xml)等内容,详细介绍C#编程工具以及visual studio 2010中的visual C# 2010开发环境。贯穿全书的分步...

    C#入门经典(第5版)

     《C#入门经典(第5版)》一书的作者karli watson是infusion development 公司高级顾问,并担任boost-net的技术架构师和it自由撰稿人、作家和开发人员。他曾编著多本-net(尤其是C#)书籍,极擅长以浅显易懂的方式阐明...

    C++标准库介绍.pdf

    检查泛型编程中concept Mpl 用模板实现元编程框架 Thread 可移植C多线程库 Python 把C类和映射到Python的中 Pool 内存池管理 smart_ptr 5个智能指针学习智能指针必读份不错参考是来自CUJ文章: Smart Poers in Boost,...

    [C#入门经典.第5版].中文.(Beginning.Visual.C#.2010).齐立波part2

    最新版的《C#入门经典(第5版)》 全面讲解C# 2010基础知识,浓墨重彩地描述web和windows编程以及数据访问(数据库和xml)等内容,详细介绍C#编程工具以及visual studio 2010中的visual C# 2010开发环境。贯穿全书的分步...

    C#入门经典第五版 part2

    最新版的《C#入门经典(第5版)》 全面讲解C# 2010基础知识,浓墨重彩地描述web和windows编程以及数据访问(数据库和xml)等内容,详细介绍C#编程工具以及visual studio 2010中的visual C# 2010开发环境。贯穿全书的分步...

    C#入门经典 part1

    最新版的《C#入门经典(第5版)》 全面讲解C# 2010基础知识,浓墨重彩地描述web和windows编程以及数据访问(数据库和xml)等内容,详细介绍C#编程工具以及visual studio 2010中的visual C# 2010开发环境。贯穿全书的分步...

Global site tag (gtag.js) - Google Analytics