Tengo muy poca idea de lo que está pasando en lo que respecta a las plantillas de C++, pero estoy tratando de implementar una función que busca un vector de un elemento de la satisfacción de una determinada propiedad (en este caso, la búsqueda de uno con el nombre que se da). Mi declaración en mi .h archivo es la siguiente:

template <typename T>
T* find_name(std::vector<T*> v, std::string name);

Al compilar, me sale este error del vinculador cuando llamo a la función:

Error   1   error LNK2019: unresolved external symbol "class Item * __cdecl find_name<class Item>(class std::vector<class Item *,class std::allocator<class Item *> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??[email protected]@@@@[email protected]@V?[email protected]@@V?[email protected]@@@[email protected]@@[email protected]@V?[email protected]?[email protected]@[email protected]@V?[email protected]@[email protected]@[email protected]@Z) referenced in function "public: class Item * __thiscall Place::get_item(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?[email protected]@@[email protected]@V?[email protected]?[email protected]@[email protected]@V?[email protected]@[email protected]@[email protected]@@Z) place.obj   Program2

De nuevo, soy nuevo en plantillas, así que no sé lo que está pasando. Todos los casos que he encontrado de LNK2019 a través de Google han estado a punto de no uso correcto de las bibliotecas, pero ya que esta es mi propia función, no veo por qué esto estaría sucediendo.

También, una pregunta relacionada: ¿hay una manera de hacer que un parámetro de plantilla por lo que tiene que ser una subclase de una clase determinada, es decir, de la plantilla?

  • qué compilador estás usando? algunos compiladores de evitar que desde la separación de la declaración y la definición en archivos separados para las plantillas.
  • Realmente escribir una implementación de la función de la plantilla?
  • También puede considerar el uso std::buscar o std::find_if
  • Pasando v y nombre de valor es costoso. Pasarlos por referencia constante en su lugar.
  • Tienes razón, Eric, yo no soy muy bueno w/ C++ todavía. Como para encontrar, se ve como algo que yo debería haber buscado más difícil, pero ¿por qué volver último si no la encuentra? No debería haber un mejor valor de retorno de un elemento inexistente?
  • nvm realmente necesito leer sobre C++
  • Sobre la devolución de última si el valor no se encuentra: De hecho, no se devuelve la «última», devuelve un iterador que denota el final de la gama, que «apunta» un pasado de la final.
  • posibles duplicados de «Undefined symbols» error del vinculador con una simple plantilla de clase

InformationsquelleAutor marsolk | 2009-10-28

6 Comentarios

  1. 73

    Tienes que tener tu definiciones de la plantilla disponible en el llamado sitio. Eso significa que no .cpp archivos.

    La razón es que las plantillas no se puede compilar. Pensar de funciones como las galletas, y el compilador es un horno.

    Plantillas son sólo un cortador de galletas, porque no saben qué tipo de cookies que son. Lo único que le dice al compilador cómo hacer la función cuando se le da un tipo, pero en sí mismo, no puede ser utilizado debido a que no hay ningún tipo concreto de ser operado. No puede cocinar un cortador de galletas. Sólo cuando se tiene la sabrosa masa de galletas listo (es decir, dado que el compilador de la masa [tipo])) puede cortar las galletas y cocinar.

    Del mismo modo, sólo cuando se utiliza realmente la plantilla con un determinado tipo puede que el compilador genere la función real, y compilarlo. No puede hacer esto, sin embargo, si la definición de la plantilla es la que falta. Tienes que mover en el archivo de encabezado, por lo que la llamada de la función puede hacer que la cookie.

    • Gracias. Ahora entiendo por que, pero me temo que no acabo de entender por qué no se puede hacer esto para regular las funciones, pero no para la plantilla de funciones, que supongo que puedo achacar a la no comprensión de C++.
    • Las plantillas son boilerplates, algo así como macros, solo lo mejor (y peor ;). Hasta y a menos que usted los usa, el compilador no es necesario hacer una macro-como reemplazo con el tipo(s) y crear la función real. Ahora, cuando el compilador de aciertos de esta creación de instancias, puede o puede no tener la repetitivo en la mano. Si no choca con un obstáculo.
    • La función de las plantillas son de no funciones. La función de las plantillas son de plantillas. Que obedezcan a sus propias reglas.
    • No es correcto decir que no se puede poner de definiciones de plantilla en .archivos cpp. Ver Charles Bailey la respuesta de abajo para una explicación más completa de la cuestión.
  2. 47

    Que son probablemente sufriendo de la falta de una válida la creación de instancias. Si usted pone su definición de la plantilla en un aparte .archivo cpp, cuando el compilador compila el archivo puede no saber que los casos que usted necesita. Por el contrario, en los sitios de llamada que iba a crear una instancia de la versión correcta de la función de la plantilla, si la definición del cuerpo de la función no está disponible por lo que el compilador no tiene la información para crear una instancia de la necesaria especialización.

    Usted tiene dos opciones. Poner el cuerpo de la función para la función de la plantilla en el archivo de encabezado.

    por ejemplo, en el archivo de encabezado:

    template <typename T>
    inline T* find_name(std::vector<T*> v, std::string name)
    {
        //...
    }

    o explícitamente crear una instancia de la plantilla en el .cpp donde se ha definido la plantilla.

    por ejemplo, en el archivo de origen (probablemente requerirá #includeing el archivo que define Item):

    template <typename T>
    T* find_name(std::vector<T*> v, std::string name)
    {
        //...
    }
    
    template Item* find_name<Item>(std::vector<Item*> v, std::string name);
    • Esto me parece más útil que la aceptó contestar debido a que gran consejo acerca de forzar la creación de instancias en el archivo de C++.
  3. 11

    Las respuestas aquí son grandes.

    Sólo voy a añadir que es por eso que además de .h y .cpp los archivos de un proyecto. Usted encontrará a menudo .inl archivos. Las definiciones de la plantilla de ir a la .inl archivo.

    Estos .inl archivos de media en línea y por lo general serán incluidos por el .h archivo con el mismo prefijo de nombre en la parte inferior del archivo, después de todo el encabezado de las declaraciones. De esta forma, los hace parte de la cabecera de archivo, pero separa las declaraciones de definiciones.

    Ya que son glorificados archivos de encabezado debe tomar todas las mismas precauciones que se tomarían con regularidad un archivo de encabezado, es decir, incluyen los guardias etc.

    • Son estos .inl archivos soportados por el estándar de C++ o son compilador-dependiente?
  4. 5

    Topó con el mismo problema y encontré este que los estados 3 soluciones:
    http://www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-a-h-file-and-imp

    Entre ellos es fácil que crear un «dummy» método en el .archivo cpp, que llama a la plantilla/función de la clase con los diferentes tipos. Pegado desde el link:

    //No need to call this TemporaryFunction() function, it's just to avoid link error.
    void TemporaryFunction ()
    {
        TestTemp<int> TempObj;
        TestTemp<float> TempObj2;
    }
    • Realmente me gusta este método, pero hay una manera de asegurarse de que el compilador no va a optimizar este asunto? Una vez traté de -O3 optimización y, a continuación, undefined symbol
  5. 1

    Me di cuenta de que había una segunda pregunta, que parece ser sin respuesta:

    Hay una manera de hacer que un parámetro de plantilla por lo que tiene que ser una subclase de una clase determinada, es decir, de la plantilla?

    Es posible. Por ejemplo, ver is_base_of en Boost.TypeTraits.

    Sin embargo, tengo curiosidad: ¿por Qué quieres eso? Normalmente, los requisitos de plantilla en sus parámetros no están en el tipo del parámetro en sí, sino en que expresiones con que tipo son legales. Por ejemplo, imagine que usted tiene:

    template<class T>
    void foo(const T& t)
    {
        if (t.foo()){
           t.bar("blah");
        }
    }

    Diciendo que T debe heredar de algo como:

    class HasFooAndBar
    {
    public:
      void foo()const;
      void bar(const char*)const;
    };

    no aporta nada, porque la ejecución de la función se producirá un error de todos modos si el tipo no apoyo a la operación. Además, innecesariamente restringe la aplicabilidad de foo(). De hecho, foo alguna requisitos son que t.foo() and t.bar(const char*) son expresiones válidas en una constante de T. Por ejemplo, este tipo no se hereda de HasFooAndBar y es todavía válido foo() parámetro:

    struct DifferentFromHasFooAndBar
    {
      bool foo()const;
      std::string bar(const std::string&)const;
    };
  6. 0

    Hizo poner su plantilla de definición de la función en un archivo cpp? A continuación, desplazarse a la cabecera y la línea es.

    • No, esto no es necesario. Ver Charles Bailey la respuesta anterior.

Dejar respuesta

Please enter your comment!
Please enter your name here