您的位置:首页 > 其它

STL为什么要提供_Int_iterator_tag

2009-10-21 03:54 197 查看
vector提供了以下两个insert重载函数.
 1). 
 template <class InputIterator>
 void insert(iterator pos, InputIterator first, InputIterator last);
 2). 
  void insert(iterator pos, size_type n, const T& x);

 vector<int> ve;
 ve.insert(ve.begin(), 3, 5);
 insert函数,编译器会调用哪个呢?
 我们的语义是要调用第二个函数,但实际上编译器并不如我们所愿,而是调用第一个
 函数,但编译器最后又怎样正确的调用第二个函数.
 为什么会调用第一个函数?
 我们先看函数模板,普通函数的重载解析优先顺序.

   同名的函数模板、模板显式特化函数和普通函数的优先选择顺序规则:
  1).如果参数类型以及返回类型完全匹配,则选择普通函数或者模板显式特化函数作为调用的函数实例。
  2).否则,如果模板函数能够推导出一个参数类型以及返回类型完全匹配的函数实例,则选择函数模板。
  3).否则,如果调用函数的实参以及返回类型能够进行隐式转换成与普通函数或者模板显式特化函数的类型匹配,
    则选择普通函数或者模板显式特化函数。
  4).如果以上三条都不能匹配,则函数匹配失败,发生编译错误。

  首先我们看ve.insert(ve.begin(), 3, 5)的参数,第一个参数为iterator,第二个与第三个参数编译器识别为int.
  1.编译器先查看参数类型是否完全匹配普通函数,结果不完全匹配 
  void insert(iterator pos, size_type n, const T& x); 因为这里的size_type其实是size_t类型(即 unsigned int).
  (注)insert函数改为 ve.insert(ve.begin(), size_t(3), 5);这样就可以直接匹配普通函数.

  2.转为模板函数,可以匹配.

  因此ve.insert(ve.begin(), 3, 5)与ve.insert(ve.begin(), ve2.begin(), ve2.end())都调用第一个模板函数.
  我们知道这两个其实是不同的功能实现.stl源码又是怎样处理这个问题的呢?

先给出vector的insert的源码:
template <class InputIterator>
void insert(iterator pos, InputIterator first, InputIterator last)   //(1)
{
__insert(pos, first, last, iterator_category(first)); //iterator_category(first)获取first的iterator类型

}

void insert(iterator pos, size_type n, const T& x)      //(2)
{
...
}

template <class InputIterator>
void __insert(iterator pos, IntIterator first, IntIterator last, _Int_iterator_tag)  //(3)
{
insert(pos, size_type(first), T(last));  //就是调用上面的第二个重载函数
}

template <class InputIterator>
void __insert(iterator pos, InputIterator first, InputIterator last, input_iterator_tag)  //(4)
{
.....
}

template <class RandomIter>
void __insert(iterator pos, RandomIter first, RandomIter last, random_access_iterator_tag) //(5)
{
....
}
    

  大家都知道iterator类型只有五种:InputIterator, OutputIterator, ForwardIterator,
  BidirectionalIterator, RandomAcessIterator.
  什么时候多出一个_Int_iteatator_tag? 其实看名字就可以知道是整数类型.
_Int_iterator_tag的定义很简单:
   struct _Int_iterator_tag
 { // identifying tag for integer types, not an iterator
 };

 现在思路应该很清楚了,ve.insert(ve.begin(), 3, 5)调用(1)函数,iterator_category(first)
 识别出为_Int_iterator_tag,再调用(3)函数,最后调用(2)函数.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息