2011-01-21 27 views
13

No he utilizado las características avanzadas de C++ por un tiempo y estoy refrescando mi conocimiento de C++ .. Habiendo dicho eso, el concepto de rasgos y programación basada en políticas fue algo que nunca logré realmente para entender.C++ ejemplo de rasgos para esta clase

Quiero cambiar eso. Estoy escribiendo un contenedor genérico. Quiero aplicar una política que indique que el contenedor almacenará solo las clases que se derivan de una clase base particular. Esto se debe a que el contenedor devuelve un objeto no válido (en lugar de tirar) cuando se intenta acceder a un elemento fuera de los límites del vector.

template <class T> 
class GenericContainer 
{ 
private: 
    typedef std::vector<T> TypeVect; 
    void addElement(const T& elem); 

    TypeVect m_elems; 

public: 
    unsigned int size() const; 
    T& elementAt(const unsigned int pos); 
    const T elementAt(const unsigned int pos) const; 
}; 

¿Cómo iba a utilizar para restringir los rasgos de este contenedor genérico para contener sólo subclases de la clase 'ContainerItem' decir?

+1

El estándar (C++ 0x) instalación de esto es 'plantilla struct is_base_of;' –

+0

is_base_of también se pueden encontrar en impulso y TR1 para los compiladores que carecen de C++ apoyo 0x – Grizzly

Respuesta

12

Puede utilizar un poco de plantilla IsDerivedFrom que sólo se pueden crear instancias en caso de un tipo 'D' dada hereda otra 'B' (esta implementación fue tomado de un nice Guru Of The Week article) Tipo:

template<typename D, typename B> 
class IsDerivedFrom 
{ 
    static void Constraints(D* p) 
    { 
    B* pb = p; // this line only works if 'D' inherits 'B' 
    pb = p; // suppress warnings about unused variables 
    } 

protected: 
    IsDerivedFrom() { void(*p)(D*) = Constraints; } 
}; 

// Force it to fail in the case where B is void 
template<typename D> 
class IsDerivedFrom<D, void> 
{ 
    IsDerivedFrom() { char* p = (int*)0; /* error */ } 
}; 

Ahora puede simplemente una instancia de la plantilla mediante IsDerivedFrom herencia:

template <class T> 
class GenericContainer : public IsDerivedFrom<T, ContainerItem> 
{ 
    ... 
}; 

Este código sólo si compila T hereda ContainerItem.

+0

+1 para la línea B * pb = p; que acentúa la restricción de compilación y hace que las clases no deseadas fallen al compilarse. –

+1

Me hizo rascar la cabeza por un tiempo ... ¡esto es realmente hermoso !. ¡Gracias! – skyeagle

5

Puede aplicar esto usando boost::mpl para afirmar en tiempo de compilación que un tipo hereda de una base.

El "hágalo usted mismo" es bastante simple:

template <typename D, typename B> 
class is_derived_from { 
    class No { }; 
    class Yes { No no[2]; }; 

    static Yes Test(B*); 
    static No Test(...); 
public: 
    enum { inherits = sizeof(Test(static_cast<D*>(0))) == sizeof(Yes) }; 
    static bool is_derived() { return inherits; } 
}; 

Creo que esto vino de GoTW originalmente. Todo lo que necesita entonces es un mecanismo de afirmación adecuado (el tiempo de compilación es probablemente mejor). El truco habitual para esto es crear una macro que crea una matriz con tamaño negativo para fallar la afirmación o 1 para pasarla.

+0

Por ahora, Quiero una solución que no involucre BOOST. Quiero saber cómo "hacer mi propio" – skyeagle

+0

actualizado con su propio rollo. – Flexo

3

Creo que está buscando la verificación del concepto. Esto estaba por construirse en C++ 0x, pero se ha pospuesto. Las bibliotecas de Boost contain a library para administrar conceptos, pero está lejos de ser un caramelo de sintaxis.

Nota al margen: tenga cuidado con el corte del objeto en su contenedor. En caso de que quiera permitir que las clases base y derivada se almacenen en el contenedor, use punteros en lugar de los objetos en sí.

2

Los rasgos de tipo y la programación basada en políticas son temas distintos. Los rasgos de tipo agregan nueva información sobre los tipos y tipos existentes que no pueden contener información adicional (cualquier construcción interna). El diseño basado en políticas es un método de diseño de clases para que pueda ensamblarlas de diversas maneras para crear diferentes comportamientos; es una especie de patrón de estado en tiempo de compilación.

Cuestiones relacionadas