Программирование >>  Полиморфизм без виртуальных функций в с++ 

1 ... 110 111 112 [ 113 ] 114 115 116 ... 144


дублироваться, если шаблон используется с одними и теми же аргументами в разных единицах трансляции. Я считал маловероятным, что при раннем (или даже позднем) инстанцировании шаблона возможно будет поискать, не инстанцирован ли тот же шаблон с другими аргументами, и определить, когда можно разделять инстанцированный код полностью или частично. И все же было чрезвычайно важно избежать такого неоправданного увеличения кода, которое встречается при расширении макросов и в языках с примитивным механизмом инстанцирования [Stroustrup, 1988b]:

Среди прочего наследование гарантирует разделение кода между различными типами (код невиртуального базового класса разделяется всеми производными от него классами). Экземпляры шаблона не разделяют код, если только не применяется какая-либо своеобразная техника компиляции. Я не питаю надежд на скорое появление такой техники. Но можно ли воспользоваться наследованием для решения проблемы дублирования кода, возникающей из-за применения шаблонов? Для этого потребовалось производить шаблон от обычного класса. Например:

template<class Т> class vector { обобщенный тип вектора

Т* v;

int SZ; public:

vector(int);

T& elem(int i) { return v[i]; ) T& operator[](int i); ...

template<class T> class pvector : vector<void*> {

вектор указателей

производный от vector<void*> public:

pvector(int i) : vector<void*>(i) {) T*& elem(int i)

{ return (T*&) vector<void*>::elem(i); } T*& operator[](int i)

{ return (T*&) vector<void*>::operator[](i); } ...

pvector<int*> pivec(lOO); pvector<complex*> icmpvec(200); pvector<char*> pcvecOOO);

Реализации всех трех классов вектора указателей полностью разделяются. Все они написаны исключительно с помощью наследования и встраивания на основе класса vector<void*>. Реализация же vec tor<void* > - один из серьезных кандидатов на включение в стандартную библиотеку .

Благодаря описанной технике удалось предотвратить неоправданное увеличение объема кода. Те, кто не пользовался чем-то подобным (в С++ или в других языках со сходными средствами параметризации типов), сталкивались с неприятным



сюрпризом: на дублированный код могли уходить мегабайты памяти даже в программе скромного размера.

С другой стороны, я считал важным, чтобы компилятор инстанцировал лишь ге функции-члены шаблона, которые использовались реально. Напри.мер, если есть шаблон Т с функциями f и д, то ко.мпилятор должен инстанцировать только f, если g для данных аргументов шаблона не вызывается.

К тому же если вариант функции-члена будет генерироваться при данном наборе аргументов шаблона, только когда эта функция действительно вызывается, то мы повысим гибкость программы [Stroustrup, 1988b]:

Рассмотрим vect ог<Т>. Если мы хотим реализовать операцию сортировки, необходимо потребовать, чтобы для типа Т было определено некоторое отношение порядка. Так обстоит дело не для всех типов. Если бы набор операций над Т нужно было задавать в объявлении vector, пришлось бы иметь два типа векторов: один для объектов, имеющих отношение порядка, другой - для остальных. Если же множество операций над Т задавать необязательно, достаточно и одного типа. Разумеется, нельзя будет сортировать векторы из объектов типа gl ob, для которых отношение порядка не определено. Даже при вашей попытке сделать это компилятор отвергнет сгенерированную фyнкциюvector<glob>: :sort () .

15.6. Шаблоны функций

Данное средство введено из-за необходимости иметь функции-члены в шаблонах классов, а также потому, что сама концепция шаблонов без него выглядела незаконченной. Конечно, были еще и хрестоматийные примеры, вроде функции sort (). Эндрю Кениг и Алекс Степанов предложили много примеров, доказывающих необходимость шаблонов функций. Са.мым важным стоит считать пример сортировки массива:

объявление шаблона функции: template<class Т> void sort(vector<T>&);

void f(vector<int>& vi, vector<String>& vs) {

sort(vi); sort(vector<int>& v); sort(vs); sort(vector<String>& v);

определение шаблона функции template<class Т> void sort(vector<T>S: v) /*

Отсортировать элементы в порядке возрастания

Алгоритм: пузырьковая сортировка (неэффективный, но очевидный)

*/ {

unsigned int n = v.sizeO;

for (int i = 0; i<n-l; i++) for (int j=n-l; i<j; j--)



if (v[j] < v[j-l]) { переставить местами v[j] и v[j-l] Т temp = v[j]

v[j] = v[j-l] v[j-l] = temp

Как и ожидалось, шаблоны функций оказались незаменимы для поддержки шаблонов классов, когда сервисы предоставлялись обычными функциями, а не функциями-членами (например дружественными функциями, см. раздел 3.6.1).

Далее рассматриваются детали реализации шаблонов функций.

15.6.1. Выведение аргументов шаблона функции

Для шаблонов функций не нужно задавать аргументы шаблона - компилятор сам выводит их по фактическим параметрам, переданным при вызове. Разумеется, каждый аргумент шаблона, не специфицированный явно (см. раздел 15.6.2), должен однозначно определяться исходя из фактического параметра. В ходе стандартизации стало ясно, что необходимо точно определить, насколько умно должен вести себя компилятор при выведении аргументов шаблона из фактических параметров функции. Например, допустимо ли следующее:

template<class Т, int i>

Т lookup(Buffer<T,i>& b, const char* p);

int f(Buffer<int,128>S: buf, const char* p) {

return lookup(buf,p); использовать lookupO, где

111- это int, a i - 128

Ранее ответ на вопрос был отрицательным, поскольку аргументы, не являющиеся типами, нельзя было вывести. Это означает, что невозможно определить не являющуюся членом невстраиваемую функцию, которая применялась бы к шаблону класса, принимающего в качестве аргумента не-тип. Например:

template<class Т, int i> class Buffer { friend T lookup(Buffers, const char*); . ..

Здесь требуется функция, определение которой раньше было незаконно. После пересмотра данного предложения перечень конструкций, допустимых в списке аргументов шаблона функции, стал выглядеть так:

const Т

volatile Т

Т&

Т[п]



1 ... 110 111 112 [ 113 ] 114 115 116 ... 144

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика