Сделать параметр шаблона другом?
Пример:
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
Однако я не знаю, как это могло бы помочь определить альтернативную версию уплотнителя классов.
Вам действительно нужно это сделать? Если вы хотите, чтобы кто-то не вышел из вашего класса, просто добавьте комментарий и сделайте деструктор не виртуальным.