Д. Вандевурд, Н.М. Джосаттис - Шаблоны C++. Справочник разработчика (2003) (1160769), страница 46
Текст из файла (страница 46)
гевр1асе<гурепаве Т, сурепаве Моче = йейац1СМоче<Т>, сурепаве Сору = йегаи1ССору<Т>, сурепаве Ямар = бейаи1СЯмар<Т>, сурепаве 1пйг = бегаи1Г?п1С<Т>, ГуРепаве К111 = дейац1ГК111<Т» с1авв Мцгагог ( 13.10. Статические свойства В главах 15, "Классы свойств и стратегий", и 19, "Классификация типов", рассматриваются различные способы классификации типов во время компиляции. Такие характе- 244 Глава 13.
Направления дальнейшего развития ристики полезны при выборе специализаций шаблонов на основе статических свойств типа. (Например, обратите внимание на наш класс Сямсгаз св в разделе 15.3.2, стр. 305, где делаются прпытки выбора оптимальных или почти оптимальных методов копирования, обмена или пересылки элементов типа аргумента.) Некоторые разработчики языка отмечали, что, если такие "выборы специализации" стануг обычным делом, они не должны требовать сложного, определяемого пользователем кода тогда, когда все дело лишь в поиске некоторого свойства, которое и так известно компилятору. Вместо этого в языке должен быть ряд встроенных признаков типа. При наличии такого расширения приведенный ниже код мог быть действительной законченной программой на С++. Мйпс1ис)е <1овсхеазв> 1пс тайп() ( вод::соис «вМ: гкуре<ъпс>:: ьв Ыс соруаЫе « ' ~п'; вой::сопе «всб::гуре<1пг>::ъв ип1оп « '~п' з Хотя для такой конструкции можно разработать собственный синтаксис, его подгонка под синтаксис, который может определяться пользователем, могла бы обеспечить более плавный переход от существующего языка к языку, который включал бы такие (функциональные) возможности.
Однако некоторые нз статических свойств, которые можно легко обеспечить в компиляторе языка С++, могут быть не реализуемы с помощью традиционных методов классов свойств (например, определения того, является ли некоторый тнп объединением). Это аргумент в пользу включения данного элемента в язык. Другой аргумент состоит в том, что такое нововведение может значительно сократить количество памяти и машинного времени, необходимых компилятору для трансляции программ, в которых используются такие свойства.
13.11. Пользовательская диагностика инстаннирования Во многих шаблонах к параметрам неявно предъявляются определенные требования. Когда аргументы инстанцирования такого шаблона не отвечают этим требованиям, либо выдается сообщение об ошибке общего характера, либо созданный экземпляр функционирует неправильно. В первых компиляторах языка С++ сообщения об ошибках общего характера, выдаваемые во время инстанцирования шаблона, зачастую были слишком неясными (за примером обратитесь к разделу 6.6.1, стр. 98). В более поздних компиляторах сообщения об ошибках уже достаточно ясны опытным программистам дпя того, чтобы быстро найти причину ошибки, но желательно еще больше улучшить ситуацию.
Рассмотрим приведенный ниже искусственный пример (его цель — проиллюстрировать, что происходит в реальных библиотеках шаблонов). 245 13.11. Пользовательская диагностика инстанцирования Гевр1асе <Гурепаве Т> чоЫ с1еаг(Т сопзсй р) ( *р = (); lу Предполагается, что Т вЂ” это тип указателя ) Севр1асе <сурепаве Т> чоЫ соге(Т сопвсй р) ( с1еаг(р); ) севр1аге <гурепаве т> чоЫ вйсЫ1е(сурепаве Т::Хпс)ех р) ( соке(р)р ) Гевр1асе <Гурепаве Т> чойс) н)те11(Т сопнсй епч) ( Гурепаве Т::Хпс)ех 1; вйсИ1е<Т>(1); с1аез С11епс [ ри)э11с: Гурес)ей Хпе Хпс)ех; С11епе ва1п с11епгэ Хпг вайп() ( в)те11(вайл с11епе); Данный пример иллюстрирует типичное расслоение разрабатываемого программного обеспечения на несколько уровней: шаблон функции высокого уровня з)те11 ( ) зависит от такого компонента, как в1сЫ1е(), который, в свою очередь, использует функцию низшего уровня соге () .
Когда инстанцируется функция з)те11 ( ), должны инстанцироваться и все уровни ниже нее. В данном примере ошибка обнаруживается на самом глубоком (низшем) уровне: функция соге ( ) инстанцируется с типом Хпг (в результате использования с11епг:: хпс)ех из функции взлы1е ( ) ), и делается попытка разыменования значения этого типа, что является ошибкой. Правильное сообшение об ошибке 246 Глава 13. Направления дальнейшего развития общего характера включает трассировку всех уровней, ведущих к ошибке; однако эта информация может оказаться весьма громоэдкой.
Часто предлагалась такая альтернатива: вставка в шаблон самого высокого уровня устройства, которое запрещает инсганцирование более низких уровней, если известные требования на этих уровнях не удовлетворяются. Делались разные попытки реализации таких устройств в рамках существующих конструкций языка С++ (например, (3)), но они не всегда эффективны. Поэтому нет ничего удивительного в том, что по данному вопросу были предложены расширения языка. Ясно, что такое расширение можно создавать поверх функциональных средств использования статических свойств, рассмотренных выше.
Например, можно представить себе следующую модификацию шаблона функции вЬе11 ( ): Гевр1асе «Гурепаве Т> чойй вЬе11(Т соплей епч) ( вгй::Тпвгапсуаг1оп еггог( вгй:гвуре<Т>::Ьав вевЬег суре<"1пйех">, "Т вовс Ьаче ап 1пйех вевЬег Гуре"'); всй::1пвсапсуасйоп еггог( !всй:ггуре<сурепаве Т::1пйех>::йегейегепсаЬ1е, "Т::1пйех впвс Ье а ройпсег-11)<е Суре" ); Гурепаве Т::1пйех 1; 1йй1е ГТ); Псевдофункция 1пвгапсуасйоп еггог ( ) должна приводить к тому, что компилятор прервет инстанцирование (следовательно, не будет сообщений об ошибках, вызываемых конкретизацией функции взйй1е ( ) ) и выдаст данное сообщение. Этот подход, хотя и вполне осуществимый, имеет ряд недостатков.
Например, при таком описании всех свойств некоторого типа код может быстро стать громоздким. Некоторые предлагали разрешить "фиктивный код", который бы служил условием, прерывающим инстанцированне. Приведем один из множества предложенных вариантов (он не вводит новых ключевых слов). Севр1асе <Гурепаве Т> чоуй вЬе11 (Т сопвсй епч) Гевр1асе Ггу ( Гурепаве Т::Хпйех р; *р = О; ) сакс)з "Т::1пйех впвс Ье а ро1псег-11)се суре"; Гурепаве Т::1пйех 1; вййй1е (1); Идея заключается в том, что тело оператора гетпр1аге агу инстанцируется для про верки, без реальной генерации объектного кода и, если происходит ошибка, выдастся последующее сообщение об этой ошибке. К сожалению, такой механизм труд"о реализовать. 13.12. Перегруженные шаблоны классов Связано зто с тем, что, хотя генерацию кода можно подавить, остаются побочные эффекты, присущие внутренней природе компилатора, избежать влияния которых крайне сложно.
Другими словами, эта не очень значительная функциональная возможность, по-видимому, потребовала бы значительной модернизации существующей технологии компиляции. Большинство подобных схем имеют и другие недостатки. Например, многие компиляторы языка С++ могут выводить сообщения об ошибках на разных языках (английском, немецком, японском и тд.), но переводы на разные языки в исходном коде могли бы оказаться излишними.
Более того, если будет прерван процесс насгожцего инстанцнрования, а предусловие не сформулировано точно, программист может оказаться в гораздо худшей ситуации, чем при получении сообщения об ошибке общего характера (пусть даже н громоздкого). 13.12. Перегруженные шаблоны классов Вполне можно представить, что существует возможность перегружать параметры шаблонов классов. Например, можно представить следующий вариант: Сетр1асе <Сурепке Т1> с1авв Тир1е ( // Олноэлементный кортеж Севр1аке <Сурепке Т1, куренное Т2> с1авв Тир1е ( // Двухэлементный кортеж сепр1асе <сурепаше т1, сурепке т2, сурепазае тЗ> с1авв Тир1е ( // Трехэлементный кортеж В следующем разделе рассматривается применение такой перегрузки. Эта перегрузка не сводится только к тому, что меняется число параметров шаблонов (такую перегрузку можно эмулировать с помощью частичной специализации, как это сделано в главе 22, "Объекты-функции и обратные вызовы", для Рппссйопрсг).
Может меняться также и вид параметров: Сешр1аке <куренное Т1, Сурепаше Т2> с1авв Райк ( // Два поля сепр1асе <Тпс 11, 1пс 12> 248 Глава 13. Направления дальнейшего развития с1авв Райт ( // Две целочисленные константы Неофициально эта идея обсуждалась некоторыми разработчиками языка, однако официально она пока еше не была представлена на рассмотрение Комитета по стандартизации языка С++. 13.13. Параметры-списки Иногда возникает необходимость передавать список типов как один аргумент шаблона. Обычно этот список преследует одну из двух целей: объявление функции с параметризованным числом параметров или определение структуры типов с параметризованным списком членов.
Например„может потребоваться определить шаблон функции, которая находит наибольшее число из произвольного списка чисел. В возможном синтаксисе такого объявления используется лексема "многоточие", обозначающая, что последний параметр шаблона соответствуетпроизвольному числу аргументов. ()1пс1цс)е <1овсгеаж> Сетр1аге <Сурепшае Т, ... 11ве> Т сопвгй шах(Т сопвсй, Т сопвей, 11вг сопвгй) Тпе ва1п() ( вка::соцг «пах(1, 2, 3, 4) «вМ::епс)1; ) Возможны разные способы реализации такого шаблона. Вот один, не требующий новых ключевых слов, но требующий добавления нового правила, которое состоит в том, что при перегрузке шаблонов функций предпочтение отдается шаблону функции без параметра-списка.
сешр1аее <Сурепке Т> Тп11пе Т соплей пех (Т соплей а, Т соплей Ь) ( // Обычный максимум двух чисел: гесцгп а < Ь ? Ь : а; Сегпр1аее <Сурепаве Т, ... 11вг> Тп11пе т сопвсй шах(т сопвсй а, т сопвсй Ь, 11вс сопвсй х) ( гегцгп пах(а, пах(Ь,х)); ) 13.13. Параметры-списки Давайте рассмотрим по шагам, как выполняется эта работа для случая, когда вызывается функция лшх (1, 2, 3, 4 ) .