2009-03-31 31 views
30

Przykład:Dokonywanie parametru szablonu znajomego?

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

Teraz to nie działa ... Czy istnieje sposób to zrobić?

Jestem rzeczywiście próbuje dokonać ogólnej klasy uszczelniaczem takiego:

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

Znalazłem ten przykład gdzieś na tej stronie, ale nie mogę go znaleźć ... (here)

Wiem, że jest other ways robienia tego, ale właśnie teraz jestem ciekawy, czy rzeczywiście możesz zrobić coś takiego.

Odpowiedz

32

Jest to wyraźnie zabronione w standardzie, nawet jeśli niektóre wersje VisualStudio na to zezwalają.

C++ standardowe 7.1.5.3 Opracowano Specyfikatory typu, akapit 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. ]

uznaję, powyższy kod jako wzorzec do uszczelniania (uniemożliwić rozszerzenie) klasy. Istnieje inne rozwiązanie, które tak naprawdę nie blokuje rozszerzenia, ale które będzie oznaczało nieodwracalne rozszerzenie klasy. Jak widać na ADOBE Source Library:

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

z wykorzystania:

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

Chociaż umożliwia rozszerzenie jeśli naprawdę zmusić go:

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

To będzie ograniczać użytkowników z błędnie zrobić.

EDIT:

nadchodzący standard C++ 11 nie pozwala na to rodzaj argumentu zaprzyjaźnić z nieco innej składni:

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

... znowu, C++ 11 zezwala na słowo kluczowe "final", na przykład: klasa X final {...} (lub możesz sprawić, że poszczególne funkcje wirtualne staną się ostateczne). W każdym przypadku próbowałem powyższego kodu ("przyjaciel T;") z g ++ 4.8.4 _without_ the -std = C++ 11 flag i kompiluje się dobrze. –

3

Czy naprawdę musisz to zrobić? Jeśli chcesz uniemożliwić komuś wywodzenie się z klasy, po prostu dodaj komentarz i unieważnij destruktor.

+0

:) Czasami najlepsza techniczna odpowiedź nie jest wcale techniczna. –

+1

Oczywiście, ale lepiej, jeśli nielegalne użycie może być oflagowane podczas kompilacji, nieprawdaż? Jest to ta sama zasada, co użycie assert() zamiast komentarza - czy nie zgodziłbyś się, że assert() jest przydatny? –

+1

Czasem po prostu nie można uczynić destruktora nie-wirtualnym, ponieważ może on mieć klasę podstawową, w której destruktor jest wirtualny. –

16

znalazłem prosty trik deklarowania parametrów szablonu jako przyjaciele:

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 

Nie wiem jednak, jak to mogłoby pomóc w zdefiniowaniu alternatywnej wersji zgrzewarki klasowej .

+0

Czy wiesz, jak to jest zgodne z normami?Działa świetnie, dzięki za napiwek! – zennehoy

+0

Wygląda całkiem normalnie, zgadzając się ze mną, ale nie jestem standardowym guru. Ładne znalezisko! – onitake

+1

Nie do końca ... klang daje mi poniżej błąd: błąd: opracowany typ odnosi się do klasy przyjaciela TypeWrapper TypeWrapper :: type; – Viren

Powiązane problemy