Сделать параметр шаблона другом?

Пример:

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 ответа

Решение

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

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

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

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

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"
};

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

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

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

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

Другие вопросы по тегам