CSDN博客

img Cppasm

标准模板库

发表于2004/1/20 21:00:00  950人阅读

这篇文章翻译自SGI的网站,原文名为Introduction to Stand Template Library,链接为http://www.sgi.com/tech/stl/.我看后感觉对于理解一些相关概念和学习STL很有帮助就把它翻译过来了,是中英文对照的,因为我也不敢保证完全能表达原文意思,只是按自己的理解翻译出来了,希望对大家能有点帮助.

标准模板库简介(一)

标准模板库,或者STL,是一个包含容器类(container classes),算法(algorithms),和迭代器(iterator)C++类库.它提供了许多计算机科学中的基本算法和数据结构.STL是一个泛型库,也就是说它的组件都是大量参数化了的(heavily parameterized):STL中的几乎每个组件都是一个模板.在开始使用STL之前,你应当确信你明白C++中的模板是如何运作的.

容器和算法

和许多类库一样,STL包括了容器:它的目的是容纳其它对象.STL包含了vector,list,deque,set,multiset,map,multimap,hash_set,hash_multiset,hash_maphash_multimap.这些类中的每一个都是一个模板.可以被实例化来容纳任何类型的对象.例如,你可以以与使用一个普通的C数组极其相似的方式来使用vector<int>,,除了vector消除了手工管理动态内存分配之外.

vector<int> v(3);           //声明一个有三个元素的vector

v[0] = 7;

v[1] = v[0]+3;

v[2] = v[0]+v[1];          //v[0]=7,v[1]=10,v[2]=17

STL也包含了大量的算法来操纵存储在容器中数据.例如,通过使用reverse算法,你可以反转一个vector中的元素顺序.

reverse(v.begin(),v.end());     //v[0]=17,v[1]=10,v[2]=7

对于reverse的这个调用有两点值得注意.首先,它是一个全局函数,而不是一个成员函数.第二,它接受两个参数而不是一个:它操作一系列元素,而不是一个容器.在这个例子中元素范围刚好是整个容器v.

导致这两个事实的原因都是一样的:reverse,像其它STL算法一样,是与STL容器类分离的,也就是说,reverse不仅可以用来反转vector中的元素,而且可以反转list甚至C数组中的元素.下面的程序也是有效的:

double A[8] = {1.2,1.3,1.4,1.5,1.6,1.7};

reverse(A,A+6);

for(int I = 0;i < 6;i++)

       cout << “A[“ << I << “]=” << A[i];

这个例子使用了一个范围(range),就如反转一个vector的例子一样;reverse的第一个参数是一个指向该范围的开始指针,第二个参数指向该范围最后一个元素之后的位置.这个范围以[A,A+6]来标记;这个非对称的标记是用来提醒那两个端点是不同得,第一个是该范围的开始,第二个则是范围末尾之后的位置.

迭代器(Iterators)

在反转一个C数组的例子中,reverse的参数类型明显的是double*.但是如果反转一个vector或者一个list的话reverse的参数又是什么呢?reverse所声明的参数究竟是什么,以及v.begin()v.end()究竟返回的是什么?

The answer is that the arguments to reverse are iterators, which are a generalization of pointers. Pointers themselves are iterators, which is why it is possible to reverse the elements of a C array. Similarly, vector declares the nested types iterator and const_iterator. In the example above, the type returned by v.begin() and v.end() is vector<int>::iterator. There are also some iterators, such as istream_iterator and ostream_iterator, that aren't associated with containers at all.

答案就是reverse的参数为iterators,它是指针的一个泛化(generalization).指针自身就是是迭代器(iterator),所以才有可能反转一个C数组的元素.相似的,vector声明了内嵌类型(nested type)iteratorconst_iterator.在上面的例子中,v.begin()v.end()所返回的类型是vector<int>::iterator.还有一些迭代器(iterators),例如istream_iteratorostream_iterator与容器根本就没有关联.

Iterators are the mechanism that makes it possible to decouple algorithms from containers: algorithms are templates, and are parameterized by the type of iterator, so they are not restricted to a single type of container. Consider, for example, how to write an algorithm that performs linear search through a range. This is the STL's find algorithm.

      template <class InputIterator, class T>
      InputIterator find(InputIterator first, InputIterator last, const T& value) {
          while (first != last && *first != value) ++first;
          return first;
      }

迭代器(iterators)是一种使得将算法与容器进行分离成为可能的机制:算法是模板,用迭代器的类型进行参数化,所以它们并不限于单一类型的容器.例如,考虑怎样编写一个在一个范围内执行线性搜索的算法.这就是STLfind算法.

              Template<class InputIterator, class T>

              InputIterator find(InputIterator first, InputIterator last, const T& value) {

                     While(first != last && *fist != value) ++first;

                     Return first;

              }

Find takes three arguments: two iterators that define a range, and a value to search for in that range. It examines each iterator in the range [first, last), proceeding from the beginning to the end, and stops either when it finds an iterator that points to value or when it reaches the end of the range.

Find接受三个参数:两个规定了一个范围的迭代器和在该范围内要搜寻的一个值value.它在[first,last]范围内检查每一个迭代器,从开始到最后,当它找到一个指向value的迭代器或者达到末尾时就停止了.

First and last are declared to be of type InputIterator, and InputIterator is a template parameter. That is, there isn't actually any type called InputIterator: when you call find, the compiler substitutes the actual type of the arguments for the formal type parameters InputIterator and T. If the first two arguments to find are of type int* and the third is of type int, then it is as if you had called the following function.

      int* find(int* first, int* last, const int& value) {
          while (first != last && *first != value) ++first;
          return first;
      }
first和last被声明为类型InputIterator,它是一个模板参数.即,事实上没有任何一个类型叫做InputIterator:当你调用find时,编译器用实际的参数类型来替换形式类型参数InputIterator和T.如果find的头两个参数类型为int*而第三个参数类型为int的话,那么就像你调用了下列函数一样:
      int* find(int* first, int* last, const int& value) {
          while (first != last && *first != value) ++first;
          return first;
      }

Concepts and Modeling

One very important question to ask about any template function, not just about STL algorithms, is what the set of types is that may correctly be substituted for the formal template parameters. Clearly, for example, int* or double* may be substituted for find's formal template parameter InputIterator. Equally clearly, int or double may not: find uses the expression *first, and the dereference operator makes no sense for an object of type int or of type double. The basic answer, then, is that find implicitly defines a set of requirements on types, and that it may be instantiated with any type that satisfies those requirements. Whatever type is substituted for InputIterator must provide certain operations: it must be possible to compare two objects of that type for equality, it must be possible to increment an object of that type, it must be possible to dereference an object of that type to obtain the object that it points to, and so on.

概念和模型
关于模板函数的一个非常重要的问题,不仅是关于STL算法,就是可以正确替换形式模板参数的类型的集合.很明显,例如,int*或者double*可以用来替换find的形式模板参数InputIterator.同样明显的是,int或者double就不可以:find使用表达式*first,解析引用(dereference)操作符对于类型为int或者double的对象并没有任何意义.因此,基本的答案就是find隐含的定义了对于类型的要求,如果这些要求得到满足那么就可以实例化.不管什么类型替换了InputIterator都必须提供一定的操作:必须能够可以比较该类型的两个对象是否相等,必须能够对该类型的一个对象进行增加操作,必须能够对该类型的一个对象进行解析引用操作以获得它所指向的对象等等.

 

Find isn't the only STL algorithm that has such a set of requirements; the arguments to for_each and count, and other algorithms, must satisfy the same requirements. These requirements are sufficiently important that we give them a name: we call such a set of type requirements a concept, and we call this particular concept Input Iterator. We say that a type conforms to a concept, or that it is a model of a concept, if it satisfies all of those requirements. We say that int* is a model of Input Iterator because int* provides all of the operations that are specified by the Input Iterator requirements.

find并不是有这种要求的唯一一个STL算法;for_each和count以及其它算法的参数都必须满足相同的要求.这些要求都是相当的重要,所以我们给它们一个名字:我们将这种类型要求称为一个概念(concept),并将这种特殊的概念(concept)称为Input_Iterator.我们说一个类型遵循一个概念,或者它是一个概念的一个模型,如果它满足所有那些要求的话.我们说int*是Input_iterator的一个模型,因为int*提供了Input_Iterator要求所指定的所有操作.

 

Concepts are not a part of the C++ language; there is no way to declare a concept in a program, or to declare that a particular type is a model of a concept. Nevertheless, concepts are an extremely important part of the STL. Using concepts makes it possible to write programs that cleanly separate interface from implementation: the author of find only has to consider the interface specified by the concept Input Iterator, rather than the implementation of every possible type that conforms to that concept. Similarly, if you want to use find, you need only to ensure that the arguments you pass to it are models of Input Iterator. This is the reason why find and reverse can be used with lists, vectors, C arrays, and many other types: programming in terms of concepts, rather than in terms of specific types, makes it possible to reuse software components and to combine components together.

概念并不是C++语言的一部分;没有办法在一个程序中声明一个概念,或者声明一个特定类型为一个概念的一个模型.然而,概念是STL的一个极度重要的部分.使用概念使得编写将接口与实现明确分离开的程序成为可能:find的作者只需考虑由概念Input_Iterator所指定的接口,而不用考虑遵循该概念的每个可能的类型.相似的,如果你想使用find,你只需确保你所传递的参数是Input_Iterator的模型.这就是为什么find和reverse可以用于list,vector,C数组和许多其它类型的原因:根据概念(concept)而不是特定类型来编程使得我们可以重用软件组件和将组件联合在一起.

0 0

相关博文

我的热门文章

img
取 消
img