2009-03-31 2 views
30

Пример:Создание параметра шаблона друга?

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

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

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

ответ

32

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

спецификаторов типа С ++ Стандартный 7.1.5.3 выработанных с пунктом 2

3.4.4 describes how name lookup proceeds for the identifier in an elaborated-type-specifier. If the identifier resolves to a class-name or enum-name, the elaborated-type-specifier introduces it into the declaration the same way a simple-type-specifier introduces its type-name. If the identifier resolves to a typedef-name or a template type-parameter, the elaborated-type-specifier is ill-formed. [Note: this implies that, within a class template with a template type-parameter T, the declaration friend class T; is ill-formed. ]

Я понимаю, код, указанный выше в качестве шаблона для уплотнения (запретить расширение) класса. Существует еще одно решение, которое на самом деле не блокирует расширение, но оно будет равномерно отклоняться от класса. Как видно из 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() {} 
}; 

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

EDIT:

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

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

... опять же, C++ 11 допускает ключевое слово «final», например: class X final {...} (или вы можете сделать отдельные виртуальные функции окончательными). В любом случае, я пробовал код выше («friend T;») с g ++ 4.8.4 _without_ the -std = C++ 11, и он компилируется отлично. –

3

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

+0

:) Иногда лучший технический ответ не является техническим. –

+1

Уверен, но лучше, если во время компиляции можно пометить незаконное использование, не так ли? Это тот же принцип, что и использование assert() вместо комментария - не могли бы вы согласиться с тем, что assert() полезен? –

+1

Иногда вы просто не можете сделать деструктор не виртуальным, потому что он может иметь базовый класс, где деструктор виртуальный. –

16

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

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 

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

+0

Любая идея, насколько это стандартно?Отлично работает, спасибо за подсказку! – zennehoy

+0

Выглядит довольно стандартно, со мной, но я не обычный гуру. Хорошая находка! – onitake

+1

Не совсем ... clang дает мне ниже ошибку: ошибка: разработанный тип относится к typedef класс friend TypeWrapper :: type; – Viren

Смежные вопросы