Д. Вандевурд, Н.М. Джосаттис - Шаблоны C++. Справочник разработчика (2003) (1160769), страница 40
Текст из файла (страница 40)
В этом случае существует более одного шаблона й и поэтому создается набор перегрузки, содержащий лве функции, сгенерированные из шаблонов: к<1пс*> (1пс*) (сгенерированная из первого шаблона) и Т <1пс*> (1пс а *) (сгенерированная из второго шаблона). Аргумент вызова (1пть) О имеет тип 1пс*, что соответствуеттолько функции, сгенерированной из первого шаблона. Следовательно, это и есть функция, которая будет вызвана в конечном итоге.
Подобный анализ можно сделать и для второго вызова. Заметим, что выражение 0 — это пелое число, а не константный нулевой указатель. Оно становится константным нулевым указателем только после спепнального неявного преобразования, однако это преобрюованне не учитывается прн выводе аргумента шаблона. г)О Глава 12. Специализация и перегрузка 12.2.1. Сигнатуры Две функции могут сосуществовать в программе, если у них разные сигнатуры.
Определим сигнатуру как приведенную ниже информацию . 2 1. Не полностью квалифицированное имя функции (или имя шаблона функции, из которого она сгенерирована). 2. Область видимости класса или пространства имен (и, если это имя имеет внутреннее связывание, единица трансляции), в котором объявлено имя. 3. Классификация функции как сопев, эго1ас11е или сопвг эго1аг11е (если это функция-член с данным спецификатором). 4.
Типы параметров функции (перед подстановкой параметров шаблона, если функция генерируется из шаблона функции). 5. Если функция генерируется из шаблона функции, то тип ее возвращаемого значения. 6. Параметры и аргументы шаблона, если функция генерируется из шаблона функции. Это означает, что в одной и той же программе могут сосуществовать следующие шаблоны и их экземпляры: Севр1аее<еурепаве Т1, Сурепаве Т2> эгоЫ Е1(Т1, Т2); севр1асе<сурепаве т1, сурепаве т2> уоЫ б1(Т2, Т1); Севр1аее<гурепагпе Т> 1опд Е2(Т]; еевр1асе<сурепазпе т> с)таг й2(Т); Однако их не всегда можно использовать, если они объявлены в одной области видимости, поскольку при их инстанцировании возникает неоднозначность перегрузки. ()1пс1ис)е <1овсгеав> Севр1аее<еурепагпе Т1, Сурепаве Т2> тгойс) Е1(Т1, Т2) ( вес)::свис « "Е1(т1, Т2)1пяг ) Севр1аге<гурепаве Т1, Сурепаве Т2> эгоЫ Е1(Т2, Т1! ( 2 Это определение отличается от того, которое дано в стандарте С++.
однако слслсвия у ник эквнкалснгы. ) 2.2. Перегрузка шаблонов функций 211 вед::соиг « "й1(Т2, Т1)1п"; // Пока все хорошо ?пс ша1п() ( й1<сЬаг,сЬаг>('а','Ь'); // Ошибка: неоднозначность ) Здесь функция й1<Т1=сЬаг, Т2=сЬаг>(Т1,Т2) может сосуществовать с функцией й1<Т1=сЬаг, Т2=сЬаг>(Т2,Т1), однако разрешение перегрузки никогда не отдаст предпочтения одной из них.
Если зти шаблоны появляются в различных единицах трансляции, эти два экземпляра действительно могут существовать в одной и той же программе (при зтом компоновщик не должен жаловаться на двойное определение, поскольку их сигнатуры различны). // Единица транслнции 1: ()?пс1ис?е <1овсгеатп> Сешр1асе<сурепаше Т1, сурепаше Т2> чоЫ й1(Т1, Т2) ( вгс?:: соцс « "й1 (Т1, Т2 ) 1п" г ) 1с? д() ( й1<сЬаг,сЬаг>('а','Ь')г ) // Единица трансляции 2: $1пс1цс(е <1овпгеазп> сешр1асе<сурепаше Т1, Сурепаше Т2> чоЫ Й1 (Т2, Т1) ( вес?::соцс « "Й1(Т2,Т1)~п"г ехсегп чо?г? д(); // Определена в единице трансляции (1) 1пг ша1п() ( й1<сЬаг,сЬаг>('а','Ь']г д(): Глава 12. Специализация и перегрузка 212 Эта программа работает и выдает следующее: б1(Т2,Т1) Е1 (Т1, Т2) 12.2.2. Частичное упорядочение перегруженных шаблонов функций Вернемся к рассмотренному ранее примеру.
()гпс1ис)е <ховсгеав> тевр1аге<гурепаве Т> 1пс й(Т) ( тегптп 1; ) Гевр1асе<сурепаве Т> 1пс т(Т*) ( геситп 2; ) 1пг ваз.п() ( нгб: зссиг «б<хпг*>((епт*) О) «низ:епс)1; еЫз:соиг «й<16с>((1пг*) О) «вес(з зепс)1з После подстановки списков аргументов шаблонов (<1пт*> и <1пс>) разрешение перегрузки заканчивается выбором правильной вызываемой функции. Однако выбор функции происходит даже в том случае, если аргументы шаблона явно не указываются. В этом случае вступает в игру вывод аргумента шаблона. Чтобы обсудить этот механизм, несколько модифицируем функцию зааеп ( ) из предыдущего примера ()гпс1иде <1свггеазв> севр1ате<турепаве Т> 1пт й(Т) ( гегцгп 1; гевр1асе<гурепаве Т> 1пт Й(Т*) ( гегигп 2; 12.2.
Перегрузка шаблонов функций 213 1пг. вайп() ( вЫ::соус «й(0) «вМ::епс)1; все)::сопс «й((1пс*)0) «вес)::епг)1; ) Рассмотрим первый вызов (й (О) ): здесь 1пс — тип аргумента, который соответствует типу параметра первого шаблона, если заменить Т на 1пс. Однако тип параметра второго шаблона — это всегда указатель, поэтому после вывода кандидатом для вызова будет только экземпляр, сгенерированный из первого шаблона. В этом случае разрешение перегрузки тривиально. Второй вызов (б ( (1пс * ) 0 ) ) более интересен: осуществить вывод аргумента удается лля обоих шаблонов, что дает функции б<1пс'"> (1пс*) и й<1пс> (1пс*) .
В аспекте традиционного разрешения перегрузки обе функции одинаково хороши для вызова с аргументом 1пс*, что соответствует неоднозначности вызова (см. приложение Б, "Разрешение перегрузки"). Однако в таких случаях вступает в игру дополнительный критерий перегрузки. Выбирается функция, сгенерированная из "более специализированного" шаблона.
Здесь, как вы скоро увидите, второй шаблон считается более специализированным, а потому результатом работы этой программы вновь будет 12.2.3. Правила формального упорядочения В нашем последнем примере интуитивно вполне понятно, что второй шаблон "более специальный", чем первый, поскольку первый может быть подстроен почти под любой тип аргумента, тогда как второй разрешает только типы-указатели. Однако другие примеры могут оказаться не столь очевидными.
Далее описана точная процедура определения того, явлжтся ли олин шаблон, участвующий в наборе перегрузки, более специалюированным, чем другой. Отметим, однако, что это правила лишь чапллчного упорядочения: возможна ситуация, когда ни один из шаблонов не будет считаться более специализированным, чем другой. Если разрешение перегрузки должно выбирать между такими шаблонами, решение принято не будет и в программе возникнет ошибка неоднозначности. Предположим, сравниваются два шаблона функций со сходными именами бс, и бкв которые кажутся жизнеспособными для данного вызова функции.
Параметры вызова функции, которые используют аргументы по умолчанию или многоточия, игнорируются. Затем создаются два искусственных списка типов аргументов (а для шаблона функции преобразования типов — возвращаемого типа) путем подстановки каждого параметра шаблона. 1. Заменим кажлый параметр типа шаблона уникальным искусственным типом. 2. Заменим кажлый шаблонный параметр шаблона уникальным искусственным шаблоном класса. г(4 Глава 12. Специализация и перегрузка 3. Заменим каждый шаблонный параметр, не являющийся типом, уникальным искусственным значением соответствующего типа. Если вывод аргумента второго шаблона из первого синтезированного списка типов аргументов происходит успешно при точном соответствии, но не наоборот, то говорят, что первый шаблон является более специализированным, чем второй. Если вывод аргумента первого шаблона для второго синтезированного списка типов аргументов происходит успешно при точном соответствии, но не наоборот, то говорят, что второй шаблон является более специализированным, чем первый.
В ином случае (если нет ни одного успешного вывода или же оба вывода успешны) упорядочения шаблонов не происходит. Попробуем применить этот подход к двум шаблонам в предыдущем примере. Для зтих шаблонов синтезируется два списка типов аргументов путем замены шаблонных параметров описанным выше способом: (А1) и (А2*) (где А1 и А2 — уникальные искусственные типы).
Очевидно, что вывод первого шаблона для второго списка типов аргументов происходит успешно при замене А2* на Т. Однако тип Т* из второго шаблона невозможно сделать соответствующим типу А1 из первого списка, который не является типом указателя. Следовательно, формально можно заключить, что второй шаблон более специализирован, чем первый. Наконец, рассмотрим более сложный пример с использованием нескольких параметров функций. сешр1асе<пурепате Т> чоЫ с(Т*, Т сопвс* = О, ...) сешр1асе<сурепазае Т> пойд П(Т сопвг*, Т*, Т* = О) нойс) ехашр1е(1пп* р) ( п(р, р); ) Прежде всего, поскольку реальный вызов не использует параметр многоточия для первого шаблона, а последний параметр второго шаблона покрывается аргументом по умолчанию, эти аргументы при частичном упорядочении игнорируются.
Отметим, что аргумент первого шаблона по умолчанию не используется. Позтому соответствующий ' параметр участвуетв упорядочении. созданные списки типов аргументов — зто (А1*,А1 сопвп*) и (А2 сопвп*,А2*). Вывод аргументов шаблона (А1*, А1 сспвг*) дяе второго шаблона успешен при замене Т на А1 сопле, однако результирующее соответствие не точное, поскольку для вызова с<А1 сопла>(А1 сопев*, А1 сопвп*, А1 сопвп* = О) с аргументами (А1* А1 сопл с *) требуется дополнительное уточнение типов.
Точно так же нельзя найти точное соответствие при выводе аргументов шаблона для первого шаблона из списка типов аргументов (А2 сопла*, А2*). Следовательно, между двумя шаблонами нет отношения упорядо. чення и вызов неоднозначен. 215 ! 2.3. Явная специализация Формальные правила упорядочения обычно обеспечивают возможность очевидного выбора шаблонов функций. Тем не менее можно привести множество примеров, когда интуитивно очевидный выбор оказывается невозможным.
Вероятно, данные правила упорядочения в будущем могуг быть пересмотрены с тем, чтобы такие ситуации стапи разрешимыми. 12.2.4. Шаблоны и нешаблоны Шаблоны функций можно перегружать нешаблонными функциями. При прочих равных условиях при выборе реальной функции вызова нешаблонная функция предпочтительнее. Приведенный ниже пример иллюстрирует это. // дега11н/попгвр1.срр ()1пс1иг)е <всгйпд> ))Тпс1ис)е <1онггеав> севр1аге<сурепаве Т> яЫ::нсгйпд б(Т) ( гесигп "Тевр1асе"; вМ::нсгйпд й(йпсй) ( гегигп "ыопгевр1асе"; ) 1пс вайа() ( ( 1пг х = 7 нег)::соис «й(х) «еМ::епг)1; ) Результат выполнения программы: Ыопсевр1аке 12.3. Явная специализация Возможность перегружагь шаблоны функций в сочетании с правилами частичного упорядочения при выборе обеспечивающего наилучшее соответствие шаблона функции позволяет добавлять к обобщенной реализации специализированные шаблоны для повышения эффективности кода Олнако перегружать шаблоны классов нельзя.