2012-08-29 13 views
6

¿Cómo comprobar en tiempo de compilación si la clase B se deriva de std :: vector?Cómo comprobar si la clase B se deriva de la familia de clases de plantilla

template<class A> 
struct is_derived_from_vector { 
    static const bool value = ????; 
}; 

Cómo comprobar en tiempo de compilación si la clase B se deriva de la familia de plantillas?

template<class A, template<class> class Family> 
struct is_derived_from_template { 
    static const bool value = ????; 
}; 

Usando:

template<class T> struct X {}; 

struct A : X<int> {} 
struct B : std::vector<char> {} 
struct D : X<D> {} 

int main() { 
    std::cout << is_derived_from_template<A, X>::value << std::endl; // true 
    std::cout << is_derived_from_template<D, X>::value << std::endl; // true 
    std::cout << is_derived_from_vector<A>::value << std::endl; // false 
    std::cout << is_derived_from_vector<B>::value << std::endl; // true 
} 
+4

Con metaprogramming plantilla, es importante hacer explícito si se necesita un C++ solamente 03 o una solución de C++ 11 es buena (aunque no estoy seguro de que C++ 11 puede ayudar aquí) . Y como una observación inteligente, dado que nunca debe heredar de contenedores estándar, el rasgo original es simple: 'falso': P –

+0

C++ 03. Yo uso el compilador msvc 2010. Por lo tanto, acepto usar 'decltype' además. 'std :: vector' es, por ejemplo, ony. Si no conoce la solución C++ 03, entonces la solución C++ 11 también es bienvenida. –

Respuesta

12

Prueba esto:

#include <type_traits> 

template <typename T, template <typename> class Tmpl> // #1 see note 
struct is_derived 
{ 
    typedef char yes[1]; 
    typedef char no[2]; 

    static no & test(...); 

    template <typename U> 
    static yes & test(Tmpl<U> const &); 

    static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes); 
}; 

Uso:

#include <iostream> 

template<class T> struct X {}; 

struct A : X<int> {}; 

int main() 
{ 
    std::cout << is_derived<A, X>::value << std::endl; 
    std::cout << is_derived<int, X>::value << std::endl; 
} 

Nota: En la línea marcada #1, usted podría También hacer que su rasgo aceptar cualquier plantilla que tiene al menos uno, pero posiblemente más argumentos de tipo por writint:

template <typename, typename...> class Tmpl 
+0

Si usa 'template class Tmpl' y utiliza un paquete de parámetros para su función de prueba, también debería poder manejar una plantilla con cualquier cantidad de argumentos, no solo uno. –

+1

El problema con este enfoque es que solo funcionará para plantillas con un único argumento. Incluso si lo aumenta para tomar los * habituales * dos argumentos de 'std :: vector', la implementación puede agregar parámetros de plantilla adicionales (siempre que proporcione valores predeterminados para esos parámetros), por lo que no será 100% portátil –

+1

@ DavidRodríguez-dribeas: Sí, hazlo variad ... –

1

que tenía la misma situación que yo necesitaba saber si una clase se deriva de un vector (como)-clase. Desafortunadamente no hay C++ - 11 o macros variadas permitidas en mi proyecto. Así que mi solución era una mezcla de Kerrek's answer y esto article con un poco de googletest de código al final:

#include <vector> 

template <typename T> 
class is_derived_from_vector 
{ 
    typedef char Yes_t[1]; 
    typedef char No_t[2]; 

    static No_t& test(const void* const); 

    template <typename U> 
    static Yes_t& test(const std::vector<U>* const); 

public: 
    static const bool value = ((sizeof(test(static_cast<T*>(0)))) == (sizeof(Yes_t))); 
}; 

template<class T> struct X {}; 
struct A : X<int> {}; 
struct B : std::vector<char> {}; 

TEST(Example, IsDerivedFrom) 
{ 
    EXPECT_FALSE(is_derived_from_vector<A>::value); 
    EXPECT_TRUE(is_derived_from_vector<B>::value); 
} 

Una solución común para todas las plantillas Creo que no sería posible definir sin el uso de C++ - 11 o superior.

0

que estaba buscando una solución a este problema no hace mucho tiempo, y previa consulta con

modernos C++ Diseño: programación genérica y patrones de diseño aplicados

yo era capaz de construir los siguientes elementos que es más o menos similar a lo que se proporcionó en los comentarios.

#include <iostream> 
#include <type_traits> 
#include <utility> 

template <typename T, template <typename...> class U> 
struct is_derived 
{ 
private: 
    template <typename...Ts> 
    static constexpr std::true_type check(const U<Ts...>&); 
    static constexpr std::false_type check(...); 


    template <typename> 
    struct is_same 
    { 
     static constexpr bool value = false; 
    }; 

    template <typename...Ts> 
    struct is_same <U<Ts...>> 
    { 
     static constexpr bool value = true; 
    }; 

    public: 
    static constexpr bool value = 
     std::is_same<decltype(check(std::declval<T>())), 
        std::true_type>::value && 
     !is_same<T>::value; 
}; 

template <typename, typename> 
struct X 
{ 
}; 

template <typename T> 
struct Y : X <T, int> 
{ 
}; 


int main(int argc, char **argv) { 

    std::cout << std::boolalpha << is_derived<Y<int>, X>::value << std::endl; 
    std::cout << std::boolalpha << is_derived<X<int,int>, X>::value << std::endl; 
    std::cout << std::boolalpha << is_derived<int, X>::value << std::endl; 

    return 0; 
} 
Cuestiones relacionadas