Сделать параметр шаблона другом? - PullRequest
37 голосов
/ 31 марта 2009

Пример:

template<class T>
class Base {
public:
    Base();
    friend class T;
};

Теперь это не работает ... Есть ли способ сделать это?

Я на самом деле пытаюсь сделать универсальный герметик следующим образом:

class ClassSealer {
private:
   friend class Sealed;
   ClassSealer() {}
};
class Sealed : private virtual ClassSealer
{ 
   // ...
};
class FailsToDerive : public Sealed
{
   // Cannot be instantiated
};

Я где-то нашел этот пример на этом сайте, но не могу его найти ... ( здесь )

Я знаю, что есть другие способы сделать это, но сейчас мне любопытно, можете ли вы действительно сделать что-то подобное.

Ответы [ 3 ]

39 голосов
/ 31 марта 2009

Это явно запрещено в стандарте, даже если некоторые версии VisualStudio допускают это.

Стандарт C ++ 7.1.5.3 Разработанные спецификаторы типов, параграф 2

3.4.4 описывает, как происходит поиск имени для идентификатора в разработаны типа спецификатор. Если идентификатор разрешается в имя класса или имя перечисления, разработанный спецификатор типа вводит это в декларации то же самое способ простого спецификатора типа вводит его тип-имя. Если идентификатор разрешается к typedef-имени или тип-параметр шаблона, разработанный спецификатор типа плохо сформирован. [Примечание: это означает, что в шаблоне класса с шаблон типа-параметра Т, объявление класс друга T ; является плохо сформирован. ]

Я распознаю приведенный выше код как шаблон для закрытия (запрета на расширение) класса. Существует еще одно решение, которое не блокирует расширение, но помечает случайное расширение из класса. Как видно из Исходная библиотека ADOBE :

namespace adobe { namespace implementation {
template <class T>
class final
{
protected:
   final() {}
};
}}
#define ADOBE_FINAL( X ) private virtual adobe::implementation::final<T>

с использованием:

class Sealed : ADOBE_FINAL( Sealed )
{//...
};

Хотя оно позволяет расширение, если вы действительно его принудительно:

class SealBreaker : public Sealed, ADOBE_FINAL( Sealed )
{
public:
   SealBreaker() : adobe::implementation::final<Sealed>(), Sealed() {}
};

Это будет ограничивать пользователей по ошибке сделать это.

РЕДАКТИРОВАТЬ :

Предстоящий стандарт C ++ 11 позволяет вам подружиться с аргументом типа с немного другим синтаксисом:

template <typename T>
class A {
   // friend class T; // still incorrect: elaborate type specifier
   friend T;          // correct: simple specifier, note lack of "class"
};
20 голосов
/ 10 апреля 2011

Я нашел простой прием, чтобы объявить параметры шаблона друзьями:

template < typename T>
struct type_wrapper 
{ 
   typedef T type; 
}; 


template < typename T> class foo 
{ 
  friend class type_wrapper < T>::type 
};   // type_wrapper< T>::type == T

Однако я не знаю, как это могло бы помочь определить альтернативную версию уплотнителя классов.

3 голосов
/ 31 марта 2009

Вам действительно нужно это сделать? Если вы хотите, чтобы кто-то не вышел из вашего класса, просто добавьте комментарий и сделайте деструктор не виртуальным.

...