Cuando estoy escribiendo una función en una clase de plantilla, ¿cómo puedo saber cuál es mi T?

por ejemplo,

template <typename T>
ostream& operator << (ostream &out,Vector<T>& vec)
{
if (typename T == int)
}

¿Cómo puedo escribir la anterior declaración si así funciona?

  • Solo para que lo sepas, hay bastante consenso en que usted ha aceptado la respuesta equivocada. Quizás desee unaccept y elegir otra. 🙂
  • Gracias por todos tus aportes! Al principio me aceptó la typeid respuesta debido a la especialización parecía excesivo para la simple función de que yo estaba escribiendo, pero más tarde terminé haciendo la función de un poco más complicado, así que he optado por la especialización de todos modos.
InformationsquelleAutor Meir | 2009-06-14

9 Comentarios

  1. 41

    Algo como esto:

    template< class T >
    struct TypeIsInt
    {
        static const bool value = false;
    };
    
    template<>
    struct TypeIsInt< int >
    {
        static const bool value = true;
    };
    
    template <typename T>
    ostream& operator << (ostream &out,Vector<T>& vec)
    {
        if (TypeIsInt< T >::value)
        //...
    }
    • Podemos esperar que esto se ha optimizado, por lo que no tenemos un extra si en cada llamada?
  2. 11

    Desde C++11 hemos std::is_same:

    if (std::is_same<T, int>::value) ...

    Se implementa similar a la sugerida rasgo TypeIsInt sugerido en las otras respuestas,
    pero con dos tipos de comparación.

  3. 10

    Definir de manera explícita, por ejemplo:

    template <>
    ostream& operator << (ostream &out,Vector<int>& vec)
    {
    }
    • Quitar template <int> y va a estar bien.
    • gracias, por señalar en error, yo no he tocado a C++ por un tiempo, no recuerdo cómo se escribe la especialización de las plantillas.
    • No hay necesidad de una especialización de plantilla. Prefieren una sobrecarga sobre la Función de la plantilla de las especializaciones. El último puede ser sorprendente a veces. (Hay un GOTW sobre el tema)
    • +1 Plantilla de especialización es la manera de hacerlo.
  4. 10

    Más simple, la mayoría de la solución general:
    Acaba de escribir un viejo y simple sobrecarga de la función:

    ostream& operator << (ostream &out,Vector<int>& vec)
    {
    //Your int-specific implementation goes here
    }

    Esto supone que el int y noint versiones no tienen mucho código en común, como usted tiene que escribir dos implementaciones independientes.

    SI quieres usar una aplicación común de la función, con sólo un if declaración dentro de esa diferencia, el uso de Charles Bailey aplicación:

    template< class T >
    struct TypeIsInt
    {
        static const bool value = false;
    };
    
    template<>
    struct TypeIsInt< int >
    {
        static const bool value = true;
    };
    
    template <typename T>
    ostream& operator << (ostream &out,Vector<T>& vec)
    {
        if (TypeIsInt< T >::value) {
          //your int-specific code here
        }
    }

    En general, no usar typeid si no es necesario.

  5. 9

    La forma más sencilla es la de proporcionar una plantilla de especialización:

    #include <iostream>
    #include <vector>
    using namespace std;
    
    template <typename T> struct A {
    };
    
    template <typename T > 
    ostream & operator <<( ostream & os, A<T> & a  ) {
        return os << "not an int" << endl;
    }
    
    
    template <> 
    ostream & operator <<( ostream & os, A<int> & a  ) {
        return os << "an int" << endl;
    }
    
    int main() {
        A <double> ad;
        cout << ad;
        A <int> ai;
        cout << ai;
    }
    • Usted tiene un punto y coma después de la segunda función de la definición de la plantilla. También, ¿por qué prefieren especialización de plantilla a una sobrecarga?
    • Extraño que el código exacto compilado con g++ sin errores!
    • <Excepcional Estilo de C++> Si usted está escribiendo una función primaria plantilla que es probable que la necesidad de la especialización, prefieren escribir como una sola plantilla de función que nunca debe ser especializado o sobrecargado, y, a continuación, aplicar la plantilla de función en su totalidad como un simple relevo a una clase de plantilla que contiene una función estática con la misma firma. Todo el mundo puede especializarse en que ambos totalmente y parcialmente, y sin afectar a los resultados de la resolución de sobrecarga.
    • +1 Aquí también.
    • Neil, veo que has editado la respuesta, pero en lugar de quitar el punto y coma, que ha añadido otro. 🙂 Yo también estoy todavía curioso en cuanto a por qué usted prefiere función de la especialización de plantilla a una sobrecarga.
    • Ah, OK – mi cerebro era un poco lento, no. El punto y coma son, por supuesto, perrfectly legal. En cuanto a mis preferencias en este asunto yo, sinceramente, no la tengo.
    • Cuando en duda, ¿por qué no seguir GOTW consejo? 😉 Avakar vinculado a uno lo que sugiere preferir sobrecargas cuando sea posible. 🙂
    • No creo que el punto y coma son legales después de la función de la definición, al menos en C++03.
    • la sobrecarga debe ser el camino a seguir. explícita de la especialización de funciones es innecesaria la limitación y haciendo un montón de fosas
    • ellos sólo son opcionales después de la función de miembro de definiciones (en la clase), pero no como una función normal de la definición (del mismo modo, ellos no son legales después de que la plantilla de declaraciones, independientemente de si aparecen en clase o no).
    • litb, estás en lo correcto acerca de las funciones de miembros. Raro. Me pregunto por qué esto estaba permitido, especialmente desde que se permita de forma tan explícita (member-declaration = ... | function-definition ;opt).
    • A mi entender, un punto y coma después de la definición de una función que se comporten como una ‘declaración vacía’ y no hacer nada, por lo tanto es legal pero no es necesario.
    • una declaración no puede aparecer fuera de una función. Así que no sería válida también.
    • Vale la pena mencionar que C++0x añade «declaraciones vacías», lo que le permite poner el punto y coma también después de las definiciones de función

  6. 8

    De esta manera.

    ostream & operator << (ostream &out, Vector<int> const & vec)
    {
        //...
    }

    El compilador elija esta función más de la plantilla de función si pasa Vector<int>.

    Edit: he encontrado este artículo, que intenta explicar por qué preferir la sobrecarga a la plantilla de especialización.

    • +1 porque es un gran artículo, pero si usted lee «Moral #2» deberías haber hecho una plantilla de clase de especialización. No puedo creer que todos los demás simplemente ignorar este artículo o no leer «Excepcional Estilo de C++»
    • +1: Siempre prefiero la sobrecarga sobre la especialización.
  7. 6

    TypeID nunca es una buena idea. Se basa en RTTI.
    Por cierto, aquí está su respuesta :http://www.parashift.com/c++-faq-lite/plantillas.html#faq-35.7

    • Así RTTI es malo ahora? Y typeid es conocido en tiempo de compilación.
    • ¿cuál es el problema con RTTI?
    • typeid es bastante lento. Plantilla de especialización se realiza en tiempo de compilación, mientras que typeid los costos de tiempo de ejecución. Hacer su camino. Ref:velocityreviews.com/forums/…
    • RTTI es malo cuando se puede evitar. @GMan, que depende de las optimizaciones del compilador. No hay garantía de que va a suceder en tiempo de compilación. ¿Por qué no ir a por la solución que se garantiza que en tiempo de compilación? Especialmente cuando también es más convencional y menos sorprendente para la gente que lee el código? Por supuesto, como un bono, RTTI puede ser desactivado por el compilador de interruptores, por lo que puede no ser capaz de confiar en él estar allí.
    • Como he dicho, typeid() se determina en tiempo de ejecución. Mientras que la creación de instancias de plantilla se realiza en tiempo de compilación. Por lo tanto, typeid no es una buena cosa que hacer. Quien te dijo typeid es conocido en tiempo de compilación? ¿Tienen alguna referencia? Estoy bastante seguro de que typeid es conocido en tiempo de ejecución. Aquí hay una referencia: msdn.microsoft.com/en-us/library/fyf39xec.aspx
    • Lo es hasta el compilador no es el problema. Cuando escribo un código, me gustaría consultar las normas no intentarlo con mi favorito-compilador. El OP creado la construcción porque él estaba confundido ¿que mejor puede describir su problema. Uso de TypeID debe ser como mínimo como sea posible. Hasta ahora, todos nos sugieren que el OP para el uso de la plantilla de especialización en su lugar. No estoy seguro de por qué hay un cuadro verde en una respuesta con -2 votos. TypeID() se evalúa en tiempo de ejecución(según norma).
    • ¿Cómo puede typeid(int) no estar optimizado en tiempo de compilación? Tendrías que ir deliberadamente fuera de su camino para escribir un compilador donde enteros se almacenan como un objeto genérico, junto con el tipo de información. En el que caso de que usted esté de lectura de hojas de té para predecir el desempeño de código que el compilador. Es único puntero y de referencia de los tipos en los que typeid tiene que ser calculado en tiempo de ejecución, porque no puede ser polimorfismo de tiempo de ejecución en el juego.
    • es curioso que usted diga consultar la norma, pero en realidad se refieren a MSDN, que es la documentación de su favorito-compilador. Dice, «Si la expresión no es ni un puntero ni una referencia a una clase base del objeto, el resultado es un type_info de referencia que representa el tipo estático de la expresión. «
    • typeid(T) es, sin duda no se determina en tiempo de compilación. Cuando dices typeid(T)==typeid(int) tiene un tiempo de ejecución de sobrecarga para calcular typeid(T) si T no pasa a ser construido en un tipo.
    • Yo sólo tengo la referencia en una rápida búsqueda en google. VC++ no es mi compilador, soy un nativo de usuarios de Linux y, por tanto, GCC es lo que yo uso.
    • En realidad, acabo de velocidad de reloj que el aceptado la respuesta (que, presumiblemente, es lo que usted se oponga a) es el uso de typeid con un tipo, no con un objeto. Ver 5.2.8:4 en la norma. Así typeid(T) sin duda se determina en tiempo de compilación. El tipo es T, no de cualquier sub-tipo: no hay polimorfismo porque no hay ningún objeto. El aceptó responder todavía se basa en el compilador de hacer en tiempo de compilación evaluación de expresiones constantes, y eliminación de código muerto.
    • «pero si el compilador no puede optimizar que fuera, es posible que el momento de pasar a un compilador moderno…» <- no creo que esto es cierto. typeid produce un lvalue, y dará a op== cuando se los compara. un poco por el compilador para optimizar. No es que sólo se obtiene un valor int que es conocido en tiempo de compilación. El resultado es un objeto de expresión que no está garantizado a ser incluso el único (&typeid(int) no se garantiza que sea siempre la misma)
    • eso parece ser lo que sucede en el gcc (con -O3). El typeid expresiones son emitidos como constantes reparaciones, (externo para int, interna de un tipo definido por el usuario), la llamada a la comparador de una referencia externa, por lo que los muertos caso no se quita. Si el comparador de llamadas fueron insertados tal vez estaríamos en el negocio, pero no con las opciones del compilador que he usado. Me pregunto si hay algo que podría enlazar estáticamente en contra de ayuda.

  8. 3

    Uno más de la solución es:

    if(std::is_same<T, int>::value)
         //It is int
    if (std::is_same<T, double>::value)
         //It is double
    if (std::is_same<T, long double>::value)
         //It is long double
  9. 0

    Las plantillas de C++ no funcionan de esta manera. La idea general de plantillas es expresar algo que es común para una gran cantidad de diferentes tipos. Y en su caso se debe utilizar la plantilla de especialización.

    template<class T> ostream& operator<< (ostream& out, const vector<T>& v)
    {
        //your general code for all type
    }
    //specialized template
    template<> ostream& operator<< <int>(ostream& out, const vector<int>& vec)
    {
        //your specific to iny type code goes here
    }

    Entonces el compilador de C++ se llama a esta función cuando se utiliza el tipo de int y la aplicación general para cualquier otro tipo de

    std::vector<int> f(5, 5);
    std::cout << f;

Dejar respuesta

Please enter your comment!
Please enter your name here