10.7. Перегрузка шаблонов функций А
10.7. Перегрузка шаблонов функций А
Шаблон функции может быть перегружен. В следующем примере есть три перегруженных объявления для шаблона min():
// определение шаблона класса Array
// (см. раздел 2.4)
template typename Type
class Array( /* ... */ };
// три объявления шаблона функции min()
template typename Type
Type min( const ArrayType, int ); // #1
template typename Type
Type min( const Type*, int ); // #2
template typename Type
Type min( Type, Type ); // #3
Следующее определение main() иллюстрирует, как могут вызываться три объявленных таким образом функции:
#include cmath
int main()
{
Arrayint iA(1024); // конкретизация класса
int ia[1024];
// Type == int; min( const Arrayint, int )
int ival0 = min( iA, 1024 );
// Type == int; min( const int*, int )
int ival1 = min( ia, 1024 );
// Type == double; min( double, double )
double dval0 = min( sqrt( iA[0] ), sqrt( ia[0] ) );
return 0;
}
Разумеется, тот факт, что три перегруженных шаблона функции успешно объявлены, не означает, что они могут быть также успешно вызваны. Такие шаблоны могут приводить к неоднозначности при вызове конкретизированного шаблона. Например, для следующего определения шаблона min5()
template typename T
int min5( T, T ) { /* ... */ }
функция не конкретизируется по шаблону, если min5() вызывается с аргументами разных типов; при этом процесс вывода заканчивается с ошибкой, поскольку из фактических аргументов функции выводятся два разных типа для T.
int i;
unsigned int ui;
// правильно: для T выведен тип int
min5( 1024, i );
// вывод аргументов шаблона заканчивается с ошибкой:
// для T можно вывести два разных типа
min5 ( i, ui );
Для разрешения второго вызова можно было бы перегрузить min5(), допустив два различных типа аргументов:
template typename T, typename U
int min5( T, U );
При следующем обращении производится конкретизация этого шаблона функции:
// правильно: int min5( int, usigned int )
min5( i, ui );
К сожалению, теперь стал неоднозначным предыдущий вызов:
// ошибка: неоднозначность: две возможных конкретизации
// из min5( T, T ) и min5( T, U )
min5( 1024, i );
Второе объявление min5() допускает наличие у функции аргументов различных типов, но не требует этого. В нашем случае и T, и U типа int. Оба объявления шаблонов могут быть конкретизированы вызовом, в котором два аргумента функции имеют один и тот же тип. Единственный способ указать, какой шаблон более предпочтителен, устранив тем самым неоднозначность, – явно задать его аргументы. (О явном задании аргументов шаблона см. раздел 10.4.) Например:
// правильно: конкретизация из min5( T, U )
min5int, int( 1024, i );
Однако в этом случае мы можем обойтись без перегрузки шаблона функции. Поскольку шаблон min5(T,U) подходит для всех вызовов, для которых подходит min5(T,T), то одного объявления min5(T,U) вполне достаточно, а объявление min5(T,T) можно удалить. Мы уже говорили в главе 9, что, хотя перегрузка допускается, при проектировании таких функций надо быть внимательным и использовать ее только при необходимости. Те же соображения применимы и к определению перегруженных шаблонов.
В некоторых ситуациях неоднозначности при вызове не возникает, хотя по шаблону можно конкретизировать две разных функции. Если имеются следующие два шаблона для функции sum(), то предпочтение будет отдано первому даже тогда, когда конкретизированы могут быть оба:
template typename Type
Type sum( Type*, int );
template typename Type
Type sum( Type, int );
int ia[1024];
// Type == int ; sumint( int*, int ); или
// Type == int*; sumint*( int*, int ); ??
int ival1 = sumint( ia, 1024 );
Как это ни удивительно, такой вызов не приводит к неоднозначности. Шаблон конкретизируется из первого определения, так как выбирается наиболее специализированное определение. Поэтому для аргумента Type принимается int, а не int*.
Для того чтобы один шаблон был более специализирован, чем другой, оба они должны иметь одни и те же имя и число параметров, а для параметров разных типов, как, скажем, T* и T в предыдущем примере, параметр в одном шаблоне должен быть способен принять более широкое множество фактических аргументов, чем соответствующий параметр в другом. Например, для шаблона sum(Type*, int) вместо первого формального параметра функции разрешается подставлять только фактические аргументы типа “указатель”. В то же время в шаблоне sum(Type, int) первому формальному параметру могут соответствовать фактические аргументы любого типа. Первый шаблон sum(Type*, int) допускает более узкое множество аргументов, чем второй, т.е. он более специализирован, а следовательно, он и конкретизируется при вызове функции.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Перегрузка операторов
Перегрузка операторов С++ позволяет нам перегружать функции, т.е. мы можем объявлять несколько функций с одним именем в одной и той же области видимости, если они имеют различные списки параметров. Кроме того, С++ поддерживает перегрузку операторов, позволяя назначать
36. Перегрузка операций
36. Перегрузка операций Часто программы имеют дело с объектами, которые являются представлениями абстрактных понятий. К примеру, тип данных int в C++ вместе с операциями +, —, *, / и т. д. является реализацией математического понятия целых чисел. Подобные понятия чаще всего
R.13 Перегрузка
R.13 Перегрузка Говорят, что имя перегружено, если для него задано несколько различных описаний функций в одной области видимости. При использовании имени выбор правильной функции производится путем сопоставления типов формальных параметров с типами фактических
Шаг 13 - Перегрузка operator+.
Шаг 13 - Перегрузка operator+. Оператор operator-› мы уже перегружали. Результаты получились просто феерические. Давайте замучаем еще кого-нибудь и посмотрим, что получится? Давайте. Первейшим кандидатом на переопределение является оператор operator+,потому что в жизни (помимо С++) он
Перегрузка методов
Перегрузка методов Подобно другим объектно-ориентированным языкам, язык C# позволяет типу перегружать его методы. Говоря простыми словами, когда класс имеет несколько членов с одинаковыми именами, отличающихся только числом (или типом) параметров, соответствующий член
Перегрузка операций
Перегрузка операций В C#, как и в любом другом языке программирования, есть свой ограниченный набор лексем, используемых для выполнения базовых операций со встроенными типами. Так, вы знаете, что операция + применима к двум целым числам и в результате дает их сумму.//
Совет 46. Передавайте алгоритмам объекты функций вместо функций
Совет 46. Передавайте алгоритмам объекты функций вместо функций Часто говорят, что повышение уровня абстракции языков высокого уровня приводит к снижению эффективности сгенерированного кода. Александр Степанов, изобретатель STL, однажды разработал небольшой комплекс
12.3.5. Адаптеры функций для объектов-функций
12.3.5. Адаптеры функций для объектов-функций В стандартной библиотеке имеется также ряд адаптеров функций, предназначенных для специализации и расширения как унарных, так и бинарных объектов-функций. Адаптеры – это специальные классы, разбитые на следующие две
Перегрузка имен функций
Перегрузка имен функций В соответствии с правилами языка С различные функции, определенные в программе, должны иметь разные имена. Это не всегда удобно, так как могут быть несколько функций, выполняющих сходные действия, но немного отличающиеся по набору параметров.Язык
Перегрузка операторов
Перегрузка операторов Си++ позволяет вам легко вводить новые типы данных. Так, например, вы можете определить класс для работы с комплексными числами или числами в полярной системе координат. Естественно, что удобнее всего проводить вычисления с объектами таких классов
4.6.7 Перегрузка Имен Функций
4.6.7 Перегрузка Имен Функций Как правило, давать разным функциям разные имена – мысль хорошая, но когда некоторые функции выполняют одинаковую рботу над объектами разных типов, может быть более удобно дать им одно и то же имя. Использование одного имени для различных
19.11.2. Вызов функций из файла функций
19.11.2. Вызов функций из файла функций Мы уже рассматривали, каким образом функции вызываются из командной строки. Эти типы функций обычно используются утилитами, создающими системные сообщения.А теперь воспользуемся снова описанной выше функцией, но в этом случае
Перегрузка и универсальность
Перегрузка и универсальность Два технических приема - перегрузка (overloading) и универсальность (genericity) предлагают свои решения, направленные на достижение большей гибкости описанных выше механизмов. Рассмотрим, что же они могут дать.
Синтаксическая перегрузка
Синтаксическая перегрузка Перегрузка - это связывание с одним именем более одного содержания. Наиболее часто перегружаются имена переменных: почти во всех языках программирования различные по смыслу переменные могут иметь одно и то же имя, если они принадлежат