Подтвердить что ты не робот

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

Пример:

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

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

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

4b9b3361

Ответ 1

Он явно запрещен в стандарте, даже если некоторые версии VisualStudio разрешают его.

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

3.4.4 описывает, как поиск имени продолжается для идентификатора в разработаны типа спецификатор. Если идентификатор разрешает имя класса или имя-имя, специфицированный спецификатор типа вводит он в декларации тот же путь, который вводит простой тип-спецификатор его тип-имя. Если идентификатор разрешается к имени typedef или тип шаблона шаблона, специфицированный тип-спецификатор плохо сформирован. [Примечание: это означает, что, внутри шаблона класса с шаблон типа-параметра T, объявление друга класса 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() {}
};

Это позволит пользователям ошибочно сделать это.

ИЗМЕНИТЬ:

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

template <typename T>
class A {
   // friend class T; // still incorrect: elaborate type specifier
   friend T;          // correct: simple specifier, note lack of "class"
};

Ответ 2

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

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

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