|
Программирование >> Обобщенные обратные вызовы
Случай 1 выглядит более привлекательно и безопасно - он работает почти на всех современных компиляторах, кроме gcc. Отступление: проблема в пространстве имен Заметим, что если бы интересующий нас шаблон функции не находился в другом пространстве имен, то мы бы могли спокойно использовать случай 1 практически на всех современных компиляторах. пример 8-3: checked delete не в пространстве имен Больше нет boost:: tempiate<typename т> void checked delete( T* x ) { II... прочий код ... delete x; boost: больше не нужен class Test { friend void checked delete<Test>( rest* x ); i nt main() { checked delete( new Test ); Результаты исследования приведены в табл. 8.3. Таблица 8.3. Результат компиляции примера 8-3 разными компиляторами
Итак, проблема для большинства компиляторов, которые не могут скомпилировать пример 8-1, заключается в том, что в нем специализация шаблона функции объявляется в другом пространстве имен. Два неверных обходных пути Когда этот вопрос только появился в Usenet, некоторые предлагали использовать объявление using (или, что то же самое, директиву using) и сделать объявление друга неквалифицированным. namespace boost { tempiate<typename т> void checked delete( T* x ) { ... остальной код ... delete x; using boost::checked delete; или using namespace boost; class Test { -TestO { } He специализация шаблона! friend void checked delete( Test* x ); Это объявление друга относится к случаю 4: 4. В противном случае имя должно быть неквалифицированным и объявляет (возможно, повторно) обычную (нешаблонную) функцию. В действительности у нас получилось объявление новой нешаблонной функции : :checked delete(Test*) в объемлющем пространстве имен. Если вы попытаетесь использовать этот код, многие из рассматривавшихся компиляторов отвергнут его, сообщая, что функция checked delete не определена, и все они сообщат об ошибке, если вы попытаетесь использовать отношение дружбы и поместить вызов закрытого члена в шаблон boost: :checked delete. И наконец, один эксперт предложил немного изменить рассмотренный код - используя одновременно using и синтаксис шаблона о. namespace boost { template<typename т> void checked delete( т* x ) { ... остальной код delete x; using boost::checked delete; или usi ng namespace boost; class Test { -TestO { } friend void checked delete<>( Test* x ); Корректно? Вероятно, этот код не совсем корректен: в стандарте нет указания на то, является ли корректным такое изменение, так что вопрос остается открытым и комитет по стандартизации языка еще не принял окончательного решения по этому вопросу. Скорее всего, этот код все же будет признан некорректным, а пока все KOMnnjiHTopbi, с которыми я имел дело, отвергли его. Почему этот код некорректен? Будем последовательны. Директива using существует для того, чтобы облегчить использование (use) имен - для вызова функций и применения имен типов в объявлениях переменных и параметров. Объявления должны подчиняться другим правилам. Аналогично тому, как вы должны объявлять специализацию шаблона в том же пространстве имен, что и сам шаблон (это нельзя делать в другом пространстве имен посредством using), вы должны и объявлять специализацию шаблона другом при помощи указания исходного пространства имен шаблона (без всяких using). Резюме Для объявления специализации шаблона функции в качестве друга вы можете использовать один из двух способов. из примера 8-1 friend void boost::checked delete ( Test* x ); из примера 8-2: добавление о или <Test> fri end void boost::checked delete<>( Test* x ); или <Test> В данной задаче продемонстрировано, что цена сокращения записи путем отбрасывания о или <Test> слишком высока - это существенная потеря переносимости. > Рекомендация Говорите то, что думаете. Указывайте, чего именно вы хотите добиться. Будьте точны. Если вы говорите о шаблоне и возникает вопрос, чего именно вы хотите добиться, - включите список (возможно, пустой) параметров шаблона. Избегайте темных углов языка программирования, включая конструкции, которые несмотря на свою корректность склонны вводить в заблуждение программистов и даже компиляторы. При объявлении специализации шаблона функции другом явно указывайте, как минимум, пустые угловые скобки о, например: namespace boost { tempiate<typename т> void checked deleteC т* x ); class Test { fri end void boost::checked delete (Test*x); плохо friend void boost::checked delete<>(Test*x); хорошо Если ваш компилятор пока что не позволяет вам использовать ни один из этих способов для объявления отношения дружбы, сделайте необходимую функцию(и) открытой - добавив при этом комментарий, почему именно это сделано, и не забудьте вернуть все на место, когда новая версия вашего компилятора позволит вам справиться с рассмотренным синтаксисом. Имеются и другие обходные пути, но уж очень неприятные и длинные. Например, можно создать прокси-класс внутри пространства имен boost и сделать другом его.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |