Программирование >>  Обобщенные обратные вызовы 

1 ... 10 11 12 [ 13 ] 14 15 16 ... 84


так что здесь вполне применим ваш опыт работы с перегрузкой обычных функций С++. Компилятор рассматривает все видимые шаблоны функций и выбирасг из них наиболее подходящий.

Специализация шаблонов функций существенно менее интуитивна. Во первых, вы не можете частично их специализировать - вместо этого вы должны использовать перегрузку. Во-вторых, специализации шаблонов функций не перегружаются. Это означает, что любые специализации, написанные вами, не влияют на выбор используемого шаблона, что противоречит интуитивным ожиданиям большинства программистов. В конце концов, если вместо специализации вы напишете обычную функцию с той же сигнатурой, то при разрешении перегрузки будет использована именно она, поскольку обычная функция всегда имеет преимущество перед шаблоном.

Если вы пишете шаблон функции, то лучше писать его как шаблон функции, никогда не специализируемый и не персфужаемый, и реализовать посредство.м шаблона класса. Этот своеобразный уровень косвенности позволит вам избежать ограничений и темных закутков шаблонов функций, а профаммисты, использующие ваш шаблон, смогут как угодно - полностью ли, частично ли - специализировать шаблон класса, никак не влияя при этом на работу шаблона функции. Таким образом вы обходите как запрет на частичную специализацию шаблона функции, так и невозможность (иногда неожиданную) перефузки специализации шаблона функции. Проблема решена.

Если вы используете обычный шаблон функции (не реализованный через шаблон класса), то для того, чтобы ваша специализированная версия данной функции принимала участие в перегрузке, вы должны сделать ее не специализацией шаблона, а обычной нешаблонной функцией с той же сигнатурой.



Задача 8. Дружественные шаблоны Сложность: 4

Если вы захотите объявить специализацию шаблона функции в качестве друга, как вы поступите? Согласно стандарту С++, вы должны воспользоваться одним из двух синтаксически корректных способов. В мире же реальных компиляторов один способ под-держивается слабо, зато второй работает со всеми текущими версиями распространенных компиляторов... за исключением одного.

Допустим, у нас есть шаблон функции, которая делает нечто с объектом. В частности, рассмотрим шаблон функции boost: :checked delete из [Boost], который удаляет переданный ему объект; среди прочего, этот шаблон вызывает деструктор объекта.

namespace boost {

tempiate<typename т> void checked delete( T* x ) { ... некоторые действия ... delete x;

Допустим, что теперь вы хотите использовать этот шаблон с классом, у которого

интересующая операция (в случае шаблона boost: :checked delete ....... деструктор)

оказывается закрытой.

class Test {

-TestО { } Закрытая (private) функция!

Test* t = new Test;

boost::checked.....delete( t ); Ошибка: деструктор класса

Test закрытый, поэтому он не может быть вызван в шаблоне checked delete

Решение простое: надо сделать checked delete другом класса Test. (Единственная альтернатива заключается в том, чтобы сделать деструктор класса Test открытым.) Что может быть проще?

И в самом деле, в стандарте С++ предусмотрено два законных и простых способа сделать это. Если, конечно, ваш компилятор будет не против...

Вопрос для новичка

1. Укажите очевидный, удовлетворяющий стандарту синтаксис объявления boost: :checked delete другом класса Test.

Вопрос для профессионала

2. Почему очевидный способ на практике оказывается ненадежным? Укажите более надежный вариант.

Решение

Эта задача - проверка на соответствие теории и практики. Сделать другом шаблон из другого пространства имен - это гораздо легче сказать (в стандарте), чем сделать (с использованием реального компилятора).

В связи с этим у меня для вас есть одна хорошая новость, одна плохая и, чтобы подбодрить вас, еще одна хорошая новость.

Хорошая новость: существует два отличных стандартных способа выполнить поставленную задачу, причем их синтаксис вполне естественен.



Плохая новость: ни один из них не работает на всех современных компиляторах. Даже известные как наиболее соответствующие стандарту компиляторы не позволят вам воспользоваться как минимум одним, а то и обоими стандартными способами.

Хорошая новость: один из способов работает на всех проверенных мною компиляторах - кроме gcc.

Итак, приступим. Исходная попытка

1. Укажите очевидный, удовлетворяющий стандарту синтаксис объявления boost: :checked delete другом класса Test.

Эта задача возникла как следствие вопроса, который задал в Usenet Стефан Бори (Stephan Born), когда пытался добиться того же, чего хотим добиться и мы. Его проблема заключалась в том, что когда он пытался сделать специализацию boost:: checked del ete другом своего класса Test, код не работал на его компиляторе.

Ниже представлен его исходный текст.

Пример 8-1: попытка добиться дружбы

class Test { -Test О { }

friend void boost::checked delete( Test* x );

Увы, этот код не работал не только на компиляторе автора вопроса, но и на ряде других компиляторов. Коротко говоря, объявление в примере 8-1 обладает следующими характеристиками:

оно соответствует стандарту, но полагается на темный угол языка;

оно отвергается многими компиляторами, в том числе очень хорошими;

его легко исправить таким образом, чтобы он перестал зависеть от темных углов и работал практически на всех современных компиляторах (кроме gcc).

Я готов приступить к пояснению четырех способов объявления друзей в С++. Это просто. Я также хочу показать вам, как поступают реальные компиляторы, и завершить рассмотрение этого вопроса написанием наиболее переносимого кода.

В темных углах

2. Почему очевидный способ на практике оказывается неиалежны.м? Укажите более надежный вариант.

При объявлении друзей имеется четыре возможности (перечисленные в [С-Ы-ОЗ], §14.5.3). Они сводятся к следующему.

Когда вы объявляете друга, не пользуясь ключевым словом template:

1. Если имя друга выглядит как имя специализации шаблона с явными аргументами (например, Name<SomeType>),

то другом является указанная специализация шаблона.

2. Иначе, если имя друга квалифицировано с использованием имени класса или пространства имен (например Some::Name) этот класс или пространство имен содержит подходящую нешаблонную функцию,

то другом является эта функция.



1 ... 10 11 12 [ 13 ] 14 15 16 ... 84

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика