Дальнейший материал предназначен для разработчиков, использующих Microsoft Visual C++ (MSVC) версий 4-6. В Visual C++ .NET перечисленные проблемы отсутствуют.
Шаблоны функций классов в STL
Допустим, у вас есть два вектора объектов Widget
, требуется скопировать объекты Widget
из одного вектора в конец другого. Задача решается легко — достаточно воспользоваться интервальной функцией insert
контейнера vector
:
vector
…
vw1.insert(vw1.end, vw2.begin, vw2.end); // Присоединить к vw1 копию
// объектов Widget из vw2
Аналогичную операцию можно выполнить с контейнерами vector
и deque
:
vector
deque
…
vw.insert(vw.end, dw.begin, dw.end); // Присоединить к vw копию
// объектов Widget из dw
Оказывается, эту операцию можно выполнить независимо от того, в каких контейнерах хранятся копируемые объекты. Подходят даже нестандартные контейнеры:
vector
…
list
…
vw.insert(vw.begin, lw.begin, lw.end); // Присоединить к vw копию
// объектов Widget из lw
set
…
vw.insert(vw.begin, sw.begin, sw.end); // Присоединить к vw копию
// объектов Widget из sw
template
typename Allocator = allocator
class SpecialContainer{…}; // STL-совместимого контейнера
SpecialContainer
vw.insert(vw.begin, scw.begin, scw.end); // Присоединить к vw копию
// объектов Widget из scw
Подобная универсальность объясняется тем, что интервальная функция insert
контейнера range
вообще не является функцией в общепринятом смысле. Это шаблон функции контейнера, специализация которого с insert
. Для контейнера vector
шаблон insert
объявлен в Стандарте следующим образом:
template
class vector {
public:
…
template
void insert(iterator position, InputIterator first, InputIterator last);
};
Каждый стандартный контейнер должен поддерживать шаблонную версию интервальной функции insert
. Аналогичные шаблоны также обязательны для интервальных конструкторов и для интервальной формы assign
(см. совет 5).
MSVC версий 4-6
К сожалению, в реализации STL, входящей в комплект поставки версий 4-6, шаблоны функций не объявляются. Библиотека изначально разрабатывалась для MSVC версии 4, а этот компилятор, как и большинство компиляторов того времени, не обладал поддержкой шаблонов функций классов. При переходе от MSCV4 к MSVC6 поддержка этих шаблонов была включена в компилятор, но вследствие судебных дел, косвенно затрагивавших фирму Microsoft, библиотека оставалась практически в неизменном состоянии.
Поскольку реализация STL, поставляемая с MSVC4-6, предназначалась для компилятора без поддержки шаблонов функций классов, авторы библиотеки имитировали эти шаблоны и заменили их конкретными функциями, которым при вызове передавались итераторы контейнера соответствующего типа. Например, шаблон insert
был заменен следующей функцией:
void insert(iterator position, // "iterator" - тип итератора
iterator first, iterator last); // для конкретного контейнера
Эта ограниченная форма интервальных функций позволяла выполнить интервальную вставку из vector
в vector
или из list
в list
, но смешанные операции (например, вставка из vector
в list
или из set
в deque
) не поддерживались. Более того, не поддерживалась даже интервальная вставка (а также конструирование или assign
) из vector
в vector
, поскольку итераторы vector
и vector
относятся к разным типам. В результате следующий фрагмент, принимаемый другими компиляторами, не компилируется в MSVC4-6:
istream_iterator
// для чтения объектов Widget
// из cin (см. совет 6).
vector
// из cin в vw (см. совет 6)
// не компилируется в MSVC4-6!
list