C++模板编程及函数对象

概述

名字空间

C++引入namespace关键字用来解决命名冲突这个问题,一个namespace就是一个作用域(scope)。C++标准库中所有的标识符都在std名字空间下,有三种方法使用这些标识符:

  1. 直接指定:

std::cout<<”Hello, world!”;

  1. 使用using声明:

#include <iostream>

using std::cout;

……

cout<<”Hello, world!”;

……

  1. 使用using指令:

include <iostream>

using namespace std;

……

cout<<”Hello, world!”;

……

 

标准容器

C++标准模板库提供了一些从用数据结构的容器,具体如下:

vector:一个类似动态数组的容器。

 

deque:和vector类似,接口基本相同,唯一不同的是deque的动态数据是两端开放,提供push_frontpop_front接口。

 

List:双向链表容器。

 

setmultiset:这两个容器中的元素会自动按指定的规则排序。set不允许出现重复的元素,而multiset可以。

 

mapmultimap:这两个容器中的元素按key/value对结构组织,以key来排序。map类似set,不允许出现key相同的元素,multimap可以。

 

其他:

basic_string:字符串模板类,为两个习惯应用定义了两个typedef

typedef basic_string<char> string;

typedef basic_wstring<wchar_t> wstring;

 

迭代器

类似于指针。是指向其他对象的对象。对于泛型算法来讲,迭代器扮演着重要的角色。通过迭代器,可以把容器和泛型算法分离出来。

 

迭代器的种类

迭代器分为输入迭代器(input iterators),输出迭代器(output iterators),前向迭代器(forward iterators),双向迭代器(bidirectional iterators)和随机访问迭代器(random access iterators)。

input iterators:只读,向C指针一样,可以比较;可以拷贝和赋值;可以使用操作符++pp++(向前移动指针)。

output iterators:只写,如同input iterators,可以拷贝和赋值;可以给output iterators写入值,如*p = x;可以使用操作符++pp++

 

forward iterators:从概念上讲,forward iterators可以运用于replace之类的算法,即可读也可写。

 

bidirectional iterator:可以使用操作符--p

 

random access iterators:随机访问迭代器有C指针的所有功能。比如:p+5p-3

 

迭代器特性

template <class Iterator>

struct iterator_traits {

typedef typename Iterator::iterator_category iterator_category;

typedef typename Iterator::value_type          value_type;

typedef typename Iterator::difference_type   difference_type;

typedef typename Iterator::pointer               pointer;

typedef typename Iterator::reference           reference;

};

 

在标准算法中会更具iterator_traits来决定针对特定迭代的算法实现,具体在标准算法部分再讨论。

 

当你定义一个新的迭代器类型时,你需要同事定义五个类型:iterator_category, value_type, difference_type, pointerreference,这五个类型应该是iterator类的嵌套类型。STL已经包含一个辅助类来作为iterator的基类,可以简化新iterator类型的定义:

template <class Category, class Value, class Distance = ptrdiff_t,

          class Pointer = Value*, class Reference = Value&>

struct iterator {

typedef Category          iterator_category;

typedef Value               value_type;

typedef Distance           difference_type;

typedef Pointer             pointer;

typedef Reference         reference;

};

 

标准算法

STL提供了许多常用的算法,这些算法都在<algorithm>头文件中定义,这里主要讲讲如何使一个泛型算法应用到不同的迭代器上。

比如一个advance算法,这个算法使迭代器向前移动指定的距离,通常的做法是为不同的迭代器定义不同的实现版本,如:

template <class InputIterator, class Distance>

void advance_II(InputIterator& i, Distance n)

{

      for ( ; n > 0; --n, ++i) {}

}

 

template <class BidirectionalIterator, class Distance>

void advance_BI(BidirectionalIterator& i, Distance n)

{

      if (n >= 0)

            for ( ; n > 0; --n, ++i) {}

      else

            for ( ; n < 0; ++n, --i) {}

}

 

template <class RandomAccessIterator, class Distance>

void advance_RAI(RandomAccessIterator& i, Distance n)

{

      if (n >= 0)

            for ( ; n > 0; --n, ++i) {}

      else

            for ( ; n < 0; ++n, --i) {}

}

 

然后在定一个外部接口:

template <class InputIterator, class Distance>

void advance_II(InputIterator& i, Distance n)

{

      if (is_random_access_iterator(i))

            advance_RAI(i, n);

      else if (is_bidirectional_iterator(i))

            advance_BI(i, n);

      else

            advance_II(i, n);

}

 

但是,现在结合iterator_traits,我们可以这样:

template <class InputIterator, class Distance>

void advance(InputIterator& i, Distance n, input_iterator_tag)

{

      //implementation

}

 

template <class BidirectionalIterator, class Distance>

void advance(BidirectionalIterator& i, Distance n, forward_iterator_tag)

{

      //implementation

}

 

template <class RandomAccessIterator, class Distance>

void advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag)

{

      //implementation

}

 

template <class InputIter, class Distance>

void advance_RAI(InputIter& i, Distance n)

{

      advance(i, n, iterator_traits<InputIter>::iterator_category());

}

 

STL定义了五个tag类型:

struct input_iterator_tag {};

struct output_iterator_tag {};

struct forward_iterator_tag: public input_iterator_tag {};

struct bidirectional_iterator_tag: public forward_iterator_tag {};

struct random_access_iterator_tag: public bidirectional_iterator_tag {};

 

函数对象

一个函数对象,就是一个包含operator ()运算符重载的对象。如:

FunctionObjectType fo;

fo(…);

 

许多标准算法提过了一个额外的参数,有些标准容器也可以接收额外的模板参数。如查找一个序列是否在是另一个序列的子序列的算法:

template<class ForwardIterator1, class ForwardIterator2>

   ForwardIterator1 search(

      ForwardIterator1 _First1,

      ForwardIterator1 _Last1,

      ForwardIterator2 _First2,

      ForwardIterator2 _Last2

   );

template<class ForwardIterator1, class ForwardIterator2, class Pr>

   ForwardIterator1 search(

      ForwardIterator1 _First1,

      ForwardIterator1 _Last1,

      ForwardIterator2 _First2,

      ForwardIterator2 _Last2

      BinaryPredicate _Comp

   );

第一个search版本只是用普通的==比较来进行查找,而第二个版本可以指定一个函数对象。

我们可以定义一个函数:

bool NoCase(char left, char right)

{

      return toupper(left) == toupper(right);

}

 

然后调用search算法:

string str(“abcdDEfG”);

string subStr(“Ddef”);

string::const_iterator iter = search(str.begin(), str.end(), subStr.begin(), subStr.end(), NoCase);

 

在看一个例子:

class NoCaseCompare

{

public:

      bool operator () (char left, char right)

      {

            return toupper(left) < toupper(right);

      }

};

 

set<string, NoCaseCompare> strSet;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值