una tipos son salida que programa pero mensajes los lexicos incorrecta esto errores error ejecuta detecta conoce compilador compila como c++ templates compiler-errors

tipos - El problema de la plantilla provoca un error del enlazador(C++)



si un programa compila y ejecuta pero da una salida incorrecta esto se conoce como un error de (6)

Tengo muy poca idea de lo que ocurre con las plantillas de C ++, pero estoy tratando de implementar una función que busque un vector para un elemento que satisfaga una propiedad dada (en este caso, busque uno con el nombre dado). Mi declaración en mi archivo .h es la siguiente:

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

Cuando compilo, obtengo este error de enlazador 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> >)" (??$find_name@VItem@@@@YAPAVItem@@V?$vector@PAVItem@@V?$allocator@PAVItem@@@std@@@std@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@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> >)" (?get_item@Place@@QAEPAVItem@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) place.obj Program2

Una vez más, soy nuevo en las plantillas, así que no sé lo que está pasando. Todas las instancias que he encontrado de LNK2019 a través de Google han consistido en no utilizar las bibliotecas correctas, pero dado que esta es mi propia función, no veo por qué sucedería esto.

Además, una pregunta relacionada: ¿hay alguna manera de hacer un parámetro de plantilla para que tenga que ser una subclase de una determinada clase, es decir, una plantilla?


¿Pusiste la definición de función de tu plantilla en un archivo cpp? Luego muévelo al encabezado y enlínealo.


Debe tener sus definiciones de plantilla disponibles en el sitio de llamada. Eso significa que no .cpp archivos .cpp .

El motivo es que las plantillas no se pueden compilar. Piensa en las funciones como cookies, y el compilador es un horno.

Las plantillas son solo un cortador de galletas, porque no saben qué tipo de cookie son. Solo le dice al compilador cómo hacer la función cuando se le da un tipo, pero en sí misma no se puede usar porque no se está operando ningún tipo concreto. No puedes cocinar un cortador de galletas. Solo cuando tenga preparada la sabrosa masa de galletas (es decir, dado el compilador la masa [tipo])) puede cortar la galleta y cocinarla.

Del mismo modo, solo cuando realmente utiliza la plantilla con un tipo determinado, el compilador puede generar la función real y compilarla. Sin embargo, no puede hacer esto si falta la definición de la plantilla. Tienes que moverlo al archivo de cabecera, para que la persona que llama de la función pueda crear la cookie.


Las respuestas aquí son geniales.

Solo .cpp que esto es a menudo por lo que además de los archivos .h y .cpp en un proyecto. A menudo encontrará archivos .inl . Las definiciones de plantilla irán al archivo .inl .

Estos archivos .inl significan en línea y generalmente estarán incluidos por el archivo .h del mismo prefijo en la parte inferior del archivo después de todas las declaraciones del encabezado. Esto los convierte efectivamente en parte del archivo de encabezado, pero separa las declaraciones de las definiciones.

Como son archivos de cabecera glorificados, debe tomar las mismas precauciones que con un archivo de cabecera normal, es decir, incluir guardias, etc.


Me di cuenta de que tenía una segunda pregunta que parece no haber sido respondida:

¿Hay alguna manera de hacer un parámetro de plantilla para que tenga que ser una subclase de cierta clase, es decir, una plantilla?

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

Sin embargo, tengo curiosidad: ¿por qué quieres eso? Normalmente, los requisitos de una plantilla en sus parámetros no están en el tipo del parámetro en sí, sino en las expresiones que implican ese tipo son legales. Por ejemplo, imagina que tienes:

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 instanciación de la función fallará de todos modos si el tipo no admite las operaciones. Además, restringe innecesariamente la aplicabilidad de foo() . De hecho, los requisitos de foo son que t.foo() and t.bar(const char*) son expresiones válidas en una const T. Por ejemplo, este tipo no hereda de HasFooAndBar y sigue siendo un parámetro foo () válido:

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


Probablemente estés perdiendo una instanciación válida. Si coloca su definición de plantilla en un archivo .cpp separado, cuando el compilador compila ese archivo, es posible que no sepa qué instancias necesita. Por el contrario, en los sitios de llamadas que instanciarían la versión correcta de la función de plantilla, si la definición del cuerpo de la función no está disponible, el compilador no tendrá la información para instanciar las especializaciones requeridas.

Tienes dos opciones. Coloque el cuerpo de la función para la plantilla de función 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 crea una instancia explícita de la plantilla en .cpp donde definiste la plantilla.

por ejemplo, en el archivo fuente (probablemente requerirá #include el archivo que define el 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);


Tropecé con el mismo problema y encontré esto que establece 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 crear un método "ficticio" en el archivo .cpp, que llama a la función de plantilla / clase con los diferentes tipos. Pegado desde el enlace:

// No need to call this TemporaryFunction() function, it''s just to avoid link error. void TemporaryFunction () { TestTemp<int> TempObj; TestTemp<float> TempObj2; }