2011-05-13 11 views
11

¿Cómo puedo determinar si un tipo se deriva de una clase de plantilla? En particular, necesito determinar si un parámetro de plantilla tiene std::basic_ostream como una clase base. Normalmente std::is_base_of es la herramienta para el trabajo. Sin embargo, std::is_base_of solo funciona para tipos completos, no para plantillas de clase.¿Cómo determinar si un tipo se deriva de una clase de plantilla?

Estoy buscando algo como esto.

template< typename T > 
bool is_based_in_basic_ostream(T&& t) 
{ 
    if(std::is_base_of< std::basic_ostream< /*anything*/>, T >::value) 
    { 
     return true; 
    } 
    else 
    { 
     return false; 
    } 
} 

Estoy seguro de que esto se puede hacer, no puedo pensar cómo.

+1

Solo quiero lanzar ... puede reemplazar esa rama if/else completa con solo una línea 'return' que devuelve la condición en la instrucción if. – AshleysBrain

+0

es 'typename T' un tipo completo? ¿Qué especificarías como '/ * cualquier cosa * /' en tu código? – iammilind

+0

En mi situación, solo esperaría ver los tipos de caracteres integrales allí. Creo que el basic_ostream no puede ser instanciado a menos que '/ * anything * /' sea un tipo completo. –

Respuesta

12

No conozco una forma breve y concisa. Pero puede abusar de la sobrecarga de nuevo

template< typename T, typename U > 
std::true_type is_based_impl(std::basic_ostream<T, U> const volatile&); 
std::false_type is_based_impl(...); 

template< typename T > 
bool is_based_in_basic_ostream(T&& t) { 
    return decltype(is_based_impl(t))::value; 
} 

Solo detectará la herencia pública. Tenga en cuenta que en su lugar puede detectar la derivación de ios_base, que puede funcionar para usted igual de bien (esta prueba también será positivo para los flujos de entrada, por lo que es de aplicabilidad limitada)

std::is_base_of<std::ios_base, T> 
+1

El problema con la comprobación de 'std :: ios_base' es que también detectaría flujos de entrada, lo que puede violar la semántica que desea OP. – ildjarn

+0

@ildjarn Estoy de acuerdo. Creo que debería haber sido más claro. Gracias por notar eso explícitamente. Reparado :) –

5

Podría algo así como is_instance_of de Boost ser lo que usted están después?

http://www.boost.org/doc/libs/1_46_1/boost/lambda/detail/is_instance_of.hpp

Aquí está la versión corta para las plantillas 1-argumento:

#include <iostream> 
#include <type_traits> 

template <template <typename> class F> 
struct conversion_tester 
{ 
     template <typename T> 
     conversion_tester (const F<T> &); 
}; 

template <class From, template <typename> class To> 
struct is_instance_of 
{ 
     static const bool value = std::is_convertible<From,conversion_tester<To>>::value; 
}; 

template <typename T> 
struct foo {}; 

template <typename T> 
struct bar {}; 

int main() 
{ 
     std::cout << is_instance_of<foo<int>,foo>::value << '\n'; // This will print '1'. 
     std::cout << is_instance_of<bar<int>,foo>::value << '\n'; // This will print '0'. 
} 

Por desgracia, si se intenta extender esto a las plantillas variadic, con GCC actual (4.6.0) se producirá un mensaje de error This SO answer implica que este es actualmente un problema de GCC y que se supone que la versión de la plantilla variadic funcionará de acuerdo con el estándar.

Cuestiones relacionadas