对于Container类,STL提供了3个重载(不同的容器可能不同,这里针对vector说明):
(1)a.insert(p,t) p---a中有效的iterator t 元素。 将t插入到p的前面
(2)a.insert(p,n,t) 和上面(1)类似,多出的n是表示元素的个数。在p的前面插入n个t
(3)a.insert(p,i , j) 和(2)一样,也是区间插入。p是a中有效的iterator,i j 是inputiterator类型。作用是将区间[i ,j)插入到iterator p之前。
看起来没什么问题。但是当我们写自己的全新的Sequence时,要知道STL实现这个的细节。这里主要是说(2)(3)两个区间插入方法的区别。
我们先来看看一个情况:如果我们要在vector<int>中批量插入int变量。例如,我们想在vector的开头插入10个0,我们可能都会这样写:v.insert(v.begin(), 10, 0)
实际上会出现什么情况呢?编译器处理,并不是我们想得到的结果。我们想的是调用上述的第二种方法来插入,但是编译器会选择第三种方法,而不是第二种方法。为什么会这样?
我们来看看vector类模板关于insert函数的定义:
iterator insert( iterator loc, const TYPE& val );
void insert( iterator loc, size_type num, const TYPE& val );
template<TYPE> void insert( iterator loc, input_iterator start, input_iterator end );
对应的就是上面我们列出的1,2,3三种方法。我们可以看到方法二的第二个参数是size_type(注意,size_type实际上就是我们常见的size_t类型)也就是unsigned int,而我们传入的参数是2个int类型变量(10,0)。因此如果编译器判断用方法二,就要进行类型转换。但是看看方法三的原型,和我们的调用完全复合。第一个参数为iterator;后面2个参数都是input_iterator类型。注意C++编译器是不知道所谓的concepts的。insert(方法三)虽然拥有名为input_iterator的模板参数型别,但是该名称在这里并没有什么特殊意义。编译器并不知道insert的参数必须是个input_iterator。它只要保证后面2个参数的类型一致就行(至于后面能否成功调用,是函数调用执行过程中的事情了)。
在我们的自定义Sequence Container中,为了解决这个问题,我们可以通过常用的重载方法来实现,例如:重载insert函数,使得第二个参数为int类型:
void insert( iterator loc,int num, const TYPE& val );
当然你可以重载很多其它的,例如改size_type为float或者其它的类型,都可以。
不过,我们可以利用前面STL所用到的Type Dispatch方法来实现,这也是某些算法所用到的思想,检查insert的引数是否为整数,如果是,就采用相应的版本。
Standard C++ Lib中的numeric_limits 类,可以很方便的用来检查某个类型是否为整数。
template< bool x > // nontype template parameters
struct dumy
{};
template< class T >
struct my_Sequence
{
void fill_insert(iterator, size_type, const value_type&);
template< class InputIter >
void range_insert(iterator, InputIter, InputIter);
template< class Number >
void insert(iterator p, Number n, Number t, dumy<true>)
{
fill_insert(p,n,t);
}
template< class InputIter >
void insert(iterator p, InputIter first, InputIter last, dumy<false>)
{
fill_insert(p, first, last);
}
void insert(iterator p, size_type n, const value_type& t)
{
fill_insert(p,n,t);
}
template< class InputIter >
void insert(iterator p, InputIter first, InputIter last)
{
insert(p, first, last , dumy<std::numeric_limits<InputIter>::is_integer>());
}
};
之所以做了这么多的额外工作,还是为了一点,提高效率。因为这个在编译的时候进行判断,而不是在运行时期通过if else进行判断,大大节省了程序运行时间。(注:使用numeric_limits类,我们需要包含头文件limits)