Анимация
JavaScript
|
Главная Библионтека php4 в 1991 году вышло первое издание книги "Эффективное использование С++" ("Effective С++"). В нем почти не рассматривались шаблоны, поскольку в то время они были новшеством, и я о них практически ничего не знал. Включенные в книгу немногочисленные фрагменты программ, содержащих шаблоны, я был вынужден посылать по электронной почте другим людям, поскольку все доступные мне компиляторы их не поддерживали. В 1995 году я написал книгу "Наиболее эффективное использование С++" ("More effective С++"). И снова почти не упомянул о шаблонах. На этот раз меня остановило не отсутствие знаний (в первоначальном варианте книга содержала целую главу, посвященную этой теме) и не ограниченность моих компиляторов. Просто возникло подозрение, что понимание роли шаблонов в среде программистов на языке С++ претерпевает настолько значительные изменения, что все мои мысли по этому поводу могут быстро стать банальными, поверхностными и даже ошибочными. Эти подозрения возникли по двум причинам. Первой из них была статья, опубликованная в январском номере журнала "С++ Report" за 1995 год Джоном Бартоном (John Barton) и Ли Нэкманом (Lee Nackman). В ней описывалось применение шаблонов для безопасного анализа размерностей (typesafe dimension analysis) без дополнительных затрат машинного времени. Я сам довольно долго пытался решить эту задачу и знал, что другие программисты также безуспешно ломают над ней голову. Революционный подход, предложенный Бартоном и Нэкменом, помог мне понять, что с помощью шаблонов можно не просто создавать контейнеры, содержащие объекты класса т, но и достичь намного более значительных результатов. В качестве иллюстрации этого подхода рассмотрим код, предназначенный для умножения двух физических величин произвольной размерности. tempiate<int ml, int 11, int tl, int m2, int 12, int t2> Physical<ml+m2, 11+12, tl+t2> operator*CPhysical<ml, 11, tl> Ihs, Physical<m2, 12, t2> rhs) return Physical<ml+m2,ll+12,tl+t2>:: unit*lhs.valueO*rhs.valueC); Даже без объяснений, приведенных в статье, совершенно очевидно, что эта шаблонная функция (function template) получает шесть параметров, ни один из которых не представляет собой какой-либо тип! Это явилось для меня приятным открытием. Вскоре я стал изучать стандартную библиотеку шаблонов STL (Standard Templates Library). Эта разработка Александра Степанова (Alexander Stepanov) весьма элегантна. В ней контейнеры ничего не знают об алгоритмах, алгоритмы ничего не знают о контейнерах, итераторы функционируют как указатели (но могут быть объектами), контейнеры и алгоритмы одинаково успешно могут получать указатели на функции и сами функции в виде объектов, а пользователи библиотеки могут расширять ее, не прибегая к наследованию от какого-либо базового класса или переопределению виртуальных функций. И тут я почувствовал (как и при чтении статьи Бартона и Нэкмена), что практически ничего не знаю о шаблонах. По этой причине я не стал почти ничего писать о шаблонах в книге "Более эффективный С++". Как я мог касаться этой темы, если мое понимание шаблонов ос- тавалось на уровне контейнеров, содержащих объекты класса т, в то время как Бар-тон, Нэкман, Степанов и другие продемонстрировали, что такое применение шаблонов является лишь вершиной айсберга? В 1998 году Андрей Александреску (Andrei Alexandrescu) и я стали обмениваться сообщениями по электронной почте, и вскоре я понял, что мне придется снова изменить свое мнение о шаблонах. В то время как Бартон, Нэкман и Степанов ошеломили меня тем, что можно сделать с помощью шаблонов, Андрей поразил меня, объяснив, как это можно сделать. Одна из простейших вещей, которые он помог мне изложить в общедоступной форме, до сих пор остается примером, который я первым привожу людям, начинающим работать в этой области. Это шаблон CTAssert, представляющий собой аналог макроса assert, но позволяющий проверять условия во время компиляции, а не во время выполнения программы. tempiate<bool> struct CTAssert; tempiateo struct CTAssert<true> {}; Вот и все! Обратите внимание на то, что обычный шаблон CTAssert нигде не определяется. Более того, он конкретизирован только для значения true, но не для false. То, что есть в этом шаблоне, не менее важно, чем то, чего в нем нет. Это заставляет посмотреть на код этого шаблона под другим углом, поскольку оказывается, что большая часть его "исходного кода" осознанно проигнорирована. Этот образ мышления совершенно отличается от общепринятого. (В этой книге Андрей обсуждает более сложный шаблон Compi 1 eXimeCheker.) В итоге Андрей приступил к разработке шаблонно-ориентированной реализации распространенных языковых идиом (language idioms) и шаблонов проектирования, особенно шаблонов GoF. Это вызвало перепалку в среде разработчиков шаблонов, поскольку они были абсолютно убеждены, что эти шаблоны невозможно запрограммировать. Когда стало ясно, что Андрей создал средства для автоматического генерирования реализаций шаблонов, а не для программирования собственно шаблонов, возражения были сняты. Мне было приятно узнать, что Андрей и один из разработчиков шаблонов GoF (Джон Влиссидес) вместе написали две статьи в журнале "С++ Report", посвященные этой теме. Следуя выбранному направлению, связанному с шаблонами для генерации идиом и реализациями шаблонов проектирования, Андрей столкнулся с проблемами, стоящими и перед другими профаммистами, работающими в этой области. Должна ли профамма быть безопасной в многопоточной системе (thread safe)? Откуда брать дополнительную память: из кучи, стека или пула статической памчи? Нужно ли перед разыменованием интеллектуальных указателей (smart pointers) проверять, равны ли они нулю? Что случится при завершении программы, если один деструктор синглтона (singltons destmctor) попытается использовать уже уничтоженный синглтон? Андрей стремился предложить пользователям максимально широкий выбор возможностей, не навязывая своего мнения. Он решил инкапсулировать эти решения в виде классов стратегий (policy classes), что позволило пользователям передавать их как шаблонные параметры. Кроме того, Андрей предложил для этих классов разумные значения по умолчанию, так что боль- Название этих шаблонов происходит от словосочетания "Gang of Four" - "Банда четырех". В состав этой "банды" входили Erich Gamma (Эрих Гамма), Richard Helm (Ричард Хелм), Ralph Johnson (Ральф Джонсон) и John Vlissides (Джон Влиссидес), написавшие основополагающую книгу Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1995), щинство клиентов может их просто игнорировать. Результат оказался потрясающим! Например, шаблон для интеллектуального указателя, описанный в книге, получает в виде параметров только 4 класса стратегий, а генерирует более 300 разных типов интеллектуальных указателей, каждый из которых обладает уникальными особенностями поведения. Программисты, осведомленные о поведении интеллектуального указателя, заданном по умолчанию, могут вообще проигнорировать параметры, представляющие собой классы стратегий, указав лишь тип объекта, на который он должен ссылаться. Это позволяет им извлекать выгоду из прекрасно сделанного класса для интеллектуального указателя, не прилагая никаких усилий. В конце книги рассмотрены три разные темы, причем для каждой из них выбран свой способ изложения. Во-первых, представлен новый взгляд на мощь и гибкость шаблонов в языке С.++. (Если, прочитав материал, посвященный спискам типов (typelists), вы не свалились со стула, значит, вы сидели на полу.) Во-вторых, указаны ортогональные направления, по которым идиомы и реализации шаблонов могут отличаться друг от друга. Для разработчиков шаблонов и программистов, занимающихся их реализацией, эта информация крайне важна, однако вы вряд ли найдете ее в других источниках. Ц заключение, читатели могут свободно загрузить исходный код библиотеки шаблонов Loki, описанной в этой книге, и изучить ее строение. С ее помощью вы можете не только испытать свой компилятор, но и начать собственную разработку. Разумеется, вы можете вполне законно использовать код, написанный Андреем, для своих целей. Я абсолютно уверен, что ему это будет приятно. Скотт Мейерс (Scott Meyers) [ 0 ] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |