促进 C++库

……其中一个世界。 赫伯·萨特安德烈亚历山德雷斯库,C++编码标准

通用编程技术

这是对一些通用的中使用的编程技术促进库。

目录

介绍

泛型编程是关于泛化软件组件,以便在多种多样的环境中轻松重用情况。在C++中,类和函数模板是泛型编程的特别有效机制因为它们使得不需要牺牲了效率。

作为泛型编程的一个简单示例,我们将看看如何概括成员()的功能C标准库。的实现成员()可能如下所示:

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(第一个!=最后一个)*结果++=*第一个++;返回结果;}

这个成员()函数已经推广到在一定程度上通过使用空隙*因此函数可用于复制不同类型数据的数组。但是,如果要复制的数据不在数组中,该怎么办?也许它在一个链接列表中。我们能概括一下复制到任何元素序列?看着尸体成员(),函数的最低要求它需要导线使用某种指针,接近指向的元素,这个元素到目的地,以及比较指向的指针知道什么时候该停下来。C++标准库组要求比如这些到概念,英寸这个案子输入迭代程序概念(用于区域2)和输出迭代程序概念(用于区域1).

如果我们重写成员()作为函数模板,并使用输入迭代程序输出迭代程序描述上的需求的概念模板参数,我们可以实现高度可重用复制()功能如下:

模板<typename InputIterator,typename OutputIter>输出迭代器copy(首先是InputIterator,最后是Input1terator,输出Iterator结果){while(第一个!=最后一个)*结果++=*第一个++;返回结果;}

使用通用复制()功能,我们现在可以从任何类型的序列复制元素,包括链接的导出迭代器的列表,如标准::列表 .

#包括<列表>#包含<矢量>#包括<iostream>整型main(){常数int N=3;标准::矢量<int>区域1(N);标准::list<int>region2;区域2.后推(1);区域2.后推(0);区域2.后推(3);标准::复制(region2.begin()、region2.end()和region1.begin;对于(int i=0;i<N;++i)标准::cout<<地区1[i]<<“”;标准::cout<<std::endl;}

a的解剖概念

A类概念是一组由有效表达式、关联类型、,不变量和复杂性保证。满足以下条件的类型这些要求被称为模型概念。一个概念可以扩展另一个概念的需求概念,称为精炼.

  • 有效表达式必须为成功编译的C++表达式要考虑的表达式中涉及的对象模型概念。
  • 关联的类型与建模类型相关的类型参与一个或多个有效表达式。通常可以通过以下方式访问关联类型typedefs嵌套在建模的类定义中类型,或通过特点.
  • 不变式是运行时特征必须始终为true的对象,即涉及对象的函数必须保留这些特点。不变量通常采用先决条件和后决条件。
  • 复杂性保证是最大限度一个有效表达式的执行时间将花费,或其计算的各种资源的多少将使用。

C++标准库中使用的概念都有文档记录C++引用网站.

特点

traits类提供了一种关联信息的方法编译时实体(类型、整型常量或地址)。例如,类模板 标准::iterator_traits看起来像这样:

模板<类迭代器>结构迭代器traits{typedef。。。迭代器类别;typedef。。。值类型;typedef。。。差异类型;typedef。。。指针;typedef。。。参考文献;};

特征值_类型为泛型代码提供迭代器“指向”的类型,而迭代器类别可用于选择更多依赖迭代器的高效算法能力。

特征模板的一个关键特性是非侵入的:它们允许我们关联信息具有任意类型,包括内置类型和类型在第三方库中定义,通常,特征是通过(部分)专门化traits模板。

为了深入描述标准::iterator_traits,请参阅第页.另一个非常不同的表达特征的习语在标准中是标准::numeric_limits它提供了描述范围和功能的常量数字类型的。

标签调度

标记调度是一种使用函数重载来基于类型属性的分派,通常手工使用与traits类密切相关。这种协同作用的一个很好的例子是实施 标准::高级()C++标准中的函数库,它增加一个迭代器n个时间。根据迭代器的类型,有不同的可以在实现中应用的优化。如果迭代器是随机的,随机的接近(可以向前和向后任意距离跳跃),然后前进()函数可以简单地使用实现i+=n,非常有效:恒定时间。其他迭代器必须是提前中的d步骤,使操作在n中线性化。如果迭代器为双向的,那么它对n个成为负数,所以我们必须决定是递增还是递减迭代器。

标签调度和特性类之间的关系是用于调度的属性(在本例中为迭代器类别)通常通过traits类。主要前进()函数使用 迭代器traits上课以获得迭代器类别。然后它调用过载高级发送()功能。这个适当的高级发送()由选择基于任何类型的编译器迭代器类别决心,要么 输入标识符标记,双向标识符标记,或随机访问标识符标记.A型标签只是一个类,其唯一目的是传递一些用于标签调度和类似操作的属性技术。请参阅第页以获取迭代器标记的更详细描述。

命名空间标准{结构input_iterator_tag{};结构双向标识符标记{};结构random_access_iterator_tag{};命名空间详细信息{模板<class InputIterator,class Distance>void advance_dispatch(InputIterator&i,距离n,输入标识符标记) {而(n-)++i;}模板<class BidirectionalIterator,class Distance>void advance_dispatch(双向迭代器&i,距离n,双向标识符标记) {如果(n>=0)而(n-)++i;其他的while(n++)--i;}模板<class RandomAccessIterator,class Distance>void advance_dispatch(RandomAccessIterator&i,距离n,随机访问标识符标记) {i+=n;}}模板<class InputIterator,class Distance>空隙提前(InputIterator&i,距离n){类别名iterator_traits<InputIterator>::iterator_category类别;详细信息::advance_dispatch(i,n,类别);}}

适配器

适配器是一个基于提供新接口或行为的另一种或多种类型变体。标准适配器的示例有标准::反向器,它通过反转迭代器的运动来适应迭代器类型增量/减量,以及标准::堆栈,它调整容器以提供简单堆栈接口。

对标准中的适配器进行更全面的审查可以找到在这里.

类型发电机

注:这个类型发生器概念具有基本上被更精细的元函数.请参阅C++模板元编程深入讨论元函数。

A类类型发生器是一个模板,其唯一目的是根据模板合成一个或多个新类型个参数[1]。生成的类型为通常表示为适当命名的嵌套typedef类型.类型生成器通常用于将复杂的类型表达式合并为简单的类型表达式。此示例使用旧版本的迭代器适配器其设计不允许派生迭代器类型。因此,每个经过调整的迭代器都必须是专业化迭代器适配器自身和发电机是生产这些类型产品的方便方法。

template<类谓词,类迭代器,类值=复杂违约,类引用=复杂违约,类指针=复杂违约,类别类别=复杂违约,类距离=复杂违约>结构filter_iterator_generator{typedef迭代器适配器<迭代器,filter_Iterator_policies<谓词,迭代器>,值、参考、指针、类别、距离>类型;};

现在,这很复杂,但产生了一个适应的过滤器使用生成器的迭代器要容易得多。你通常可以只需写下:

boost::filter_iterator_generator<my_predicate,my_base_iterator>::type

对象发电机

对象生成器是一个函数模板目的是用它的参数构造一个新的对象。将其视为一种泛型构造函数。一个物体要生成的确切类型很难或不可能express和生成器的结果可以直接传递指向函数,而不是存储在变量中。最大助力对象生成器使用前缀命名"制造_“,之后标准::生成路径(常数T&,常数U&).

例如,给定:

结构小部件{无效调整(int);};std::vector<widget*>widget_ptrs;

通过链接两个标准对象生成器,标准::绑定2()标准::内存运行(),我们可以轻松调整所有小部件:

void tweak _ all _ widgets1(int参数){for_each(widget_ptrs.begin()、widget_petrs.end()、,绑定2(标准::内存运行(&widget::tweak),arg));}

如果不使用对象生成器,上面的示例将显示这样地:

void tweak_all_widgets2(int参数){for_each(struct_ptrs.begin()、struct_pstrs.end(),标准::binder2nd(标准::mem_fun1_t<void,widget,int>(&widget::tweak),arg);}

随着表达式变得越来越复杂,需要减少类型规范的冗长变得更加引人注目。

策略类

策略类是用于传输的模板参数行为。标准库中的一个示例是标准::分配器,它提供了标准的内存管理行为容器.

以下人员详细探讨了策略类安德烈·亚历山德雷斯库在里面他的书,现代C++设计.他写入:

简而言之,基于策略的类设计促进了许多小类中具有复杂行为的类(称为策略),每个策略只处理一个行为或结构方面。顾名思义策略建立与特定问题。您可以以各种方式实施策略,只要您尊重策略界面。

因为您可以混合和匹配策略,所以可以实现通过使用小核心的组合行为集基本组件。

Andrei对策略类的描述表明功率来源于粒度和正交性。较小粒度的策略接口在尽管如此,还是要练习。这篇论文描述了旧版本的迭代器适配器使用非正交策略的。标准图书馆也有先例: 标准::char_traits,尽管它的名字,但它的作用是确定行为的策略类标准::基本字符串.

笔记

[1]类型生成器有时被视为缺乏C++中的“模板化类型定义”。