2010-01-24 8 views
10

Acabo de descubrir cómo comprobar si se proporciona operator<< para un tipo.SFINAE + sizeof = detectar si la expresión compila

template<class T> T& lvalue_of_type(); 
template<class T> T rvalue_of_type(); 

template<class T> 
struct is_printable 
{ 
    template<class U> static char test(char(*)[sizeof(
     lvalue_of_type<std::ostream>() << rvalue_of_type<U>() 
    )]); 
    template<class U> static long test(...); 

    enum { value = 1 == sizeof test<T>(0) }; 
    typedef boost::integral_constant<bool, value> type; 
}; 

¿Es este truco bien conocido, o acabo de ganar el premio Nobel de metaprogramación? ;)

EDITAR: Hice el código más simple de entender y más fácil de adaptar con dos declaraciones de plantilla de función global lvalue_of_type y rvalue_of_type.

+0

Con VC++ parece que 'is_printable :: valor' es cierto para cualquier X, y con Comeau línea que parece ser falsa para cualquier X. Con – UncleBens

+0

g ++, consigo 1 para' is_printable :: valor' y 0 para 'is_printable > :: value', por lo que funciona bien para mí. – fredoverflow

+4

por lo que funciona en 1 de cada 3 compiladores ... – UncleBens

Respuesta

5

Es una técnica bien conocida, me temo :-)

El uso de una llamada de función en el operador sizeof indica al compilador para realizar la deducción argumento y la coincidencia función, en tiempo de compilación, por supuesto. Además, con una función de plantilla, el compilador también crea una función concreta a partir de una plantilla. Sin embargo, esta expresión no hace que se genere una llamada a función. Está bien descrito en SFINAE Sono Buoni PDF.

Compruebe el otro C++ SFINAE examples.

1

Es solo una combinación de dos trucos bien conocidos. SFINAE dice que "la falla de sustitución no es un error", eso es exactamente lo que hiciste. Usar sizeof para permitir que el compilador sustituya los argumentos de la plantilla en una expresión sin ejecutarlo realmente también es común.

Lo sentimos :-)

Cuestiones relacionadas