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

1 ... 12 13 14 [ 15 ] 16 17 18 ... 84


Компилятор

Результат

Сообщение об ошибке

Metrowerks 8.2

MS VC++ 6.0

Error

nonexistent function boost::checked delete

specified as friend

MS VC++ 7.0 (2002)

MS VC++ 7.1 (2003)

MS VC++ 8.0 (2005) beta

Случай 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 разными компиляторами

Компилятор

Результат

Сообщение об ошибке

Borland 5.5

Comeau 4.3.0.1

Digital Mars 8.38

EDG 3.0.1

Intel 6.0.1

gcc 2.95.3

gcc 3.4

Metrowerks 8.2

MS VC++ 6.0

Error

syntax error (just cant handle it)



Компилятор

Результат

Сообщение об ошибке

MS VC++ 7.0 (2002)

Error

friend declaration incorrectly inteфгeted as declaring a brand-new (and undefined) ordinary nontemplate function, even though we used template syntax

MS VC++- 7.1 (2003)

MS VC++ 8.0 (2005) beta

Итак, проблема для большинства компиляторов, которые не могут скомпилировать пример 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 и сделать другом его.



1 ... 12 13 14 [ 15 ] 16 17 18 ... 84

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