2009-03-31 10 views
30

Ejemplo:Haciendo un parámetro de plantilla un amigo?

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

Ahora bien, esto no funciona ... ¿Hay una manera de hacer esto?

En realidad estoy tratando de hacer un sellador clase general de esta manera:

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

me encontré con este ejemplo en este sitio en alguna parte, pero no puedo encontrarlo ... (here)

Sé que hay other ways de hacer esto, pero ahora tengo curiosidad si realmente puedes hacer algo como esto.

Respuesta

32

Está explícitamente prohibido en el estándar, incluso si algunas versiones de VisualStudio lo permiten.

C++ estándar 7.1.5.3 elaborados especificadores de tipo, párrafo 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. ]

I reconocen el código de seguridad como un patrón para sellar (no permitir la extensión de) una clase. Hay otra solución, que realmente no bloquea la extensión, pero que indicará que se extiende de forma inadvertida desde la clase. Como se ve en ADOBE Source Library:

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

con el uso:

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

Mientras que permite la extensión si realmente lo fuerza:

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

Será evitar que los usuarios por error hacerlo.

EDITAR:

El novedoso estándar de C++ 11 no le permiten hacerse amigo de un argumento de tipo con una sintaxis ligeramente diferente:

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

... una vez más, C++ 11 permite la palabra clave "final", por ejemplo: clase X final {...} (o puede hacer funciones virtuales individuales finales). En cualquier caso, probé el código anterior ("amigo T") con g ++ 4.8.4 _without_ the -std = C++ 11 y compila bien. –

3

¿Realmente necesita hacer esto? Si desea evitar que alguien provenga de su clase, simplemente agregue un comentario y haga que el destructor no sea virtual.

+0

:) A veces, la mejor respuesta técnica no es técnica en absoluto. –

+1

Claro, pero es mejor si el uso ilegal se puede marcar en tiempo de compilación, ¿no es así? Es el mismo principio que usar un assert() en lugar de un comentario. ¿No estaría de acuerdo con que assert() es útil? –

+1

A veces no se puede hacer que el destructor sea no virtual, porque podría tener una clase base donde el destructor es virtual. –

16

me encontré con un simple truco para declarar los parámetros de plantilla como amigos:

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 

Sin embargo, no sé cómo esto podría ayudar a definir una versión alternativa de un sellador de clase .

+0

¿Alguna idea de lo estándar que es esto?Funciona muy bien, gracias por la propina! – zennehoy

+0

Parece bastante estándar, pero no soy un gurú estándar. Buen hallazgo! – onitake

+1

No del todo ... clang me da error a continuación: error: el tipo elaborado se refiere a un typedef friend class TypeWrapper :: type; – Viren

Cuestiones relacionadas