При втором вызове (для массива double b[10]) инстанцируется функция
double Summa(double const "begin, double const *end)
{ double total = doubleO; // инициализация нулем
while (begin != end)
{ total +=*begin; ++begin;
}
return total;
}
Далее компилятор «украшает» имена функций как при обычной перегрузке.
Наш шаблон был написан в предположении, что будут суммироваться элементы числовых массивов. Однако он получился более универсальным, чем задумывалось. Шаблон правильно работает для любого класса, в котором реализован конструктор без аргументов и операция operator+ — это не обязательно операция сложения. Например, корректно работает вызов с аргументом типа string:
string d[4] = {,,l+н,"2+,, ,"3+" ,"4"}; cout << Summa(d, d+4) << endl;
Результатом является строка "1+2+3+4". Стандартный класс string имеет конструктор без аргументов, а операция «сложения» является операцией сцепления.
Несмотря на то что компилятор самостоятельно выводит тип аргумента шаблона, вполне можно задать его и в явном виде, например:
cout << Summa<double>(b, b+10) << endl;
Кроме того, вывод типов не работает для типа возвращаемого значения, поэтому такой аргумент при вызове функции-шаблона всегда нужно указывать явно. Рассмотрим этот вопрос подробнее. Наш шаблон содержит одну ошибку, которую можно продемонстрировать следующим образом:
short s[2]= { 20000,20000 }; cout << Summa(s, s+2) << endl;
Результат, выводимый на экран, отрицательный, и равен -25 536. Произошло обычное переполнение, так как результат операции 20 ООО + 20 ООО = 40 ООО не помещается в переменную типа short. И такая ситуация возникает каждый раз, когда значения элементов массива находятся на границе диапазона. Нам нужно модифицировать шаблон таким образом, чтобы результат помещался в более «мощный» тип, чем тип аргументов. Однако в С++ отсутствуют стандартные средства, позволяющие выбрать «более мощный тип».
СОВЕТ
Поэтому надо добавить в шаблон Summa еще один параметр — тип возвращаемого значения (листинг 12.2).
Проблему можно решить с помощью некоторых приемов программирования шаблонов [20, 21, 28].
Листинг 12.2. Шаблон функции с параметром — типом возвращаемого значения
template <typename RT, typename T>
RT Summa(T const *begin, T const *end)
{ RT total = RT(); // инициализация нулем
while (begin != end)
{ total +=*begin; ++begin;
}
return total;
}
Теперь вызовы нужно писать с явным указанием аргумента для типа возвращаемого значения, например:
int а[10]= {1,2,3,4,5,6,7,8,9,19}; cout << Summa<long>(a, а+10) << endl; double b[10]= {1.1,2,3,4,5,6,7,8,9.10.1}; cout << Summa<double>(b, b+19) << endl; string d[4] = {"1+" , "2+M,"3+M ,"4"}; cout << Summa<string>(d, d+4) << endl; short s[2]= { 20099,29990 }; cout << Summa<int>(s, s+2) << endl;
Попытка вызвать функцию-шаблон без аргумента приводит к ошибке трансляции, например:
cout << Summa(d, d+4) << endl;
Дело в том, что тип возвращаемого значения не выводится компилятором автоматически, в отличие от типов параметров.
Обратите внимание, что параметр шаблона RT для возвращаемого значения функции указан первым. Это позволяет нам при вызове не задавать аргументы для остальных параметров — их вычисляет компилятор. Перепишем шаблон, переставив параметры:
template <typename Т, typename RT>
RT Summa(T const *begin, T const *end)
{ RT total = RT(); // инициализация нулем
while (begin != end)
{ total +=*begin; ++begin;
}
return total;
}
Теперь при вызове придется задавать все параметры явно, например:
int а[10]= {1,2,3,4,5,6,7.8,9,10};
cout << Summa<int, long>(a, а+10) << endl;
Попробуем написать вызов такого шаблона функции с одним аргументом: cout << Summa<long>(a, а+10) << endl;
В этом случае выдается ошибка компиляции (Visual C++.NET 2003):
error С2783: 'RT Summa(const T *,const T *)': could not deduce template argument for 'RT'
|