2010-09-24 29 views
6

He estado jugando con el tipo de deducción/impresión con el uso de plantillas de código del formulario:plantilla del tipo de la deducción de referencia

#include <iostream> 
template <typename T> 
class printType {}; 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const printType<T>&) 
{ 
    os << "SomeType"; return os; 
} 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const printType<T*>&) 
{ 
    os << printType<T>() << "*"; return os; 
} 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const printType<T&>&) 
{ 
    os << printType<T>() << "&"; return os; 
} 
// etc... and can call on a variable through 

template <typename T> 
printType<T> print(T) { return printType<T>(); } 

int main() 
{ 
    int a = 7; 
    int *p = &a; 
    int &r = a; 

    //OK: return SomeType* 
    std::cout << "type of p: " << print(p) << std::endl; 
    //Hmmmm: returns SomeType <- (no &: can I get around this?) 
    std::cout << "type of r: " << print(r) << std::endl; 
} 

Me pregunto si o no puedo conseguir la última línea para volver int&, es decir, ya sea:
(i) haga que la plantilla de impresión imprima deduciendo el tipo de su argumento como int& o de alguna manera funcionó debería devolver un printType<T&> cuando lo paso r; o
(ii) si esto es inevitable debido a la forma en que se pasa la variable a la función.

¿Hay alguna forma de evitar esto cambiando la forma de impresión o utilizando algún otro truco de plantilla? Si existen soluciones, preferiría no usar C++ 0x, pero siempre es bueno ver qué accesos directos estarán disponibles, si no, en el futuro.

Respuesta

9

No hay forma de solucionar esto. Una expresión p, donde p nombra una referencia, siempre tiene el tipo al que hace referencia la referencia. Ninguna expresión tiene tipo T&. Por lo tanto, no puede detectar si una expresión se originó a partir de una referencia o no.

Esto tampoco se puede hacer con C++ 0x. Es un principio profundo de C++ que no hay expresiones que tengan tipo de referencia. Usted puede escribir decltype(r) para obtener el tipo de nombres r en lugar de qué tipo tiene la expresión r. Pero no podrá escribir print(r), a menos que print sea una macro, por supuesto, pero no veo por qué seguiría ese horrible camino.

+0

Sugiero hace trampas ... ver más abajo. –

1

Tomo lo que dije anteriormente. Creo que puedo tener una forma de hacer que esto funcione en c/C++ puro, aunque de una manera muy desordenada. Se podría necesidad de pasar un puntero en sus funciones ...

es decir hola_mundo bool (std :: string & mi_cadena, const std :: string * const my_string_ptr) {

bool hola_mundo (std :: cadena mi_cadena, const std :: string * my_string_ptr const) {

si Probado

si (== & mi_cadena my_string_ptr)

Evaluaría verdadero si la var se pasó por referencia, y falso si pasó por valor.

Por supuesto duplicar sus variables en todas sus funciones, probablemente no vale la pena ...


Johannes es correcto ... no en C++ puro. Pero PUEDES hacer esto. El truco es hacer trampa. Use un lenguaje de scripting incorporado como perl para buscar su fuente. He aquí un módulo de Perl embebido:

http://perldoc.perl.org/perlembed.html

Pass es el nombre de la función, nombre de la variable, y la ubicación de origen y luego usar una expresión regular para encontrar la variable y comprobar su tipo. Realmente, esta podría ser una mejor solución para su código en general, suponiendo que siempre tendrá una fuente a mano.

Voy a publicar una función para este enfoque básico en un momento ... tengo que encargarme de un trabajo de la mañana! :)

Incluso si no desea distribuir el origen, podría crear algún tipo de archivo empaquetado de función/var que podría analizar a través de @ runtime y obtener un resultado equivalente.


Editar 1

Por ejemplo ... el uso de la función # I32 match(SV *string, char *pattern) en el tutorial de Perl Insertar, usted podría hacer algo como:

bool is_reference(const char * source_loc, const char * function_name, 
        const char * variable_name) { 
    std::ifstream my_reader; 
    char my_string[256]; 
    SV * perl_line_contents; 
    bool ret_val = false; 
    char my_pattern [400]=strcat("m/.*",function_name); 
    my_pattern=strcat(my_pattern, ".*[,\s\t]*"); 
    my_pattern=strcat(my_pattern, variable_name); 
    my_pattern=strcat(my_pattern, "[\s\t]*[\(,].*$"); 

    my_reader.open(source_loc.c_str()); 
    while (!my_reader.eof()) { 
     my_reader.getline(my_string,256); 
     sv_setpv(perl_line_contents,my_string); 
     if(match(perl_line_contents,my_pattern)) { 
      ret_val= true; 
     } 
    } 

    return ret_val; 
} 

... no .. . dos formas de hacer esto (ver la actualización anterior).

1

Puede utilizar SFINAE con tipos enteros o nada se puede convertir de "0" de esta manera:

template <typename T> 
class is_reference 
{ 
    struct yes { char a, b; }; 
    typedef char no; 

    template <typename U> static no test(T y) { } 
    template <typename U> static yes test(...) { } 

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

#include <iostream> 

struct not_constructable_from_int {}; 
struct constructable_from_int { constructable_from_int(int x) { } }; 

int 
main() 
{ 
    std::cout << is_reference<int>::value << std::endl; 
    std::cout << is_reference<int&>::value << std::endl; 

    std::cout << is_reference<not_constructable_from_int>::value << std::endl; 
    std::cout << is_reference<not_constructable_from_int&>::value << std::endl; 
    std::cout << is_reference<constructable_from_int>::value << std::endl; 
    std::cout << is_reference<constructable_from_int&>::value << std::endl; 
} 

Tenga en cuenta que la prueba es básicamente "se puede llamar a test<T>(0)", que no se puede, si es T una referencia o si T es cualquier clase que no se puede convertir de 0. Lamentablemente, siempre puedes llamar al test<T>(T()), que me sorprendió (incluso si T es).

Como se puede ver si están dispuestos a hacer sus tipos construible de int entonces la prueba funciona en ellos, lo que realmente me confunde dado el resultado test<T>(T()) ...

Cuestiones relacionadas