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的源码:
大家都知道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)函数.
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)函数.
相关文章推荐
- STL之三 iterator、iterator tag、iterator traits
- effective stl读书笔记 & stl里面提供的算法 & emplace & ostream_iterator
- C++STL为什么要有const_iterator
- STL中的iterator形参为什么不是传引用而是传值
- (原創) 为什么说iterator是left inclusive? (C/C++) (STL)
- 用C++中STL提供的fstream和stream_iterator读写二进制文件。
- (转载)用C++中STL提供的fstream和stream_iterator读写二进制文件
- STL中提供-二分查找算法(binary_search lower_bound upper_bound equal_range)
- 确保真正的线程安全——微软为什么不提供线程安全库
- c++ STL istream_iterator<> demo
- STL中的Iterator
- 为什么WinMain函数返回类型是int PASCAL?
- 为什么我们要尽可能使用Iterator接口中的remove方法而不是用Collection接口中的remove方法
- 关于STL的list,vector等用迭代器iterator,用erase删除元素出现的问题。
- (转)为什么IO读取流的read方法返回的是int而不是byte的原因!
- 用 JSP 2 提供的 SimpleTagSupport 开发自定义标签
- 【转】关于int范围中负数最小值的绝对值比整数最大值大初学C,问题源自:为什么C中的int类型(16位)的下溢下限为-32768而上溢上限却是32767。 首先说吧,32767很容易理解,32767
- 为什么是string::size_type而不是int?---顺便聊聊无符号数和负数的比较
- STL iterator 类型
- STL Iterator 迭代器