Pregunta

Tengo muy poca idea de lo que sucede con respecto a las plantillas de C ++, pero estoy tratando de implementar una función que busca en un vector un elemento que satisfaga una propiedad dada (en este caso, busca 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, aparece este error de 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> >)" (??$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

Nuevamente, soy nuevo en plantillas, así que no sé qué está pasando. Todas las instancias que he encontrado de LNK2019 a través de Google se han tratado de no usar las bibliotecas correctas, pero como esta es mi propia función, no veo por qué sucedería esto.

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

¿Fue útil?

Solución

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

El motivo es que las plantillas no se pueden compilar. Piense 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í mismo, no se puede usar porque no se está operando ningún tipo concreto. No puedes cocinar un cortador de galletas. Solo cuando tenga lista la sabrosa masa para galletas (es decir, dado el compilador de la masa [tipo])) puede cortar la galleta y cocinarla.

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

Otros consejos

Probablemente estés sufriendo por perder una instancia 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 crearían una instancia de 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.

p. en el archivo de encabezado:

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

o crear una instancia explícita de la plantilla en el archivo .cpp donde definió la plantilla.

p. en el archivo fuente (probablemente requerirá #include ing 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);

Las respuestas aquí son geniales.

Solo agregaré que esto es a menudo la razón, además de los archivos .h y .cpp en un proyecto. A menudo encontrarás archivos .inl . Las definiciones de plantilla irán al archivo .inl .

Estos archivos .inl significan en línea y generalmente se incluirán en el archivo .h del mismo prefijo en la parte inferior del archivo después de todas las declaraciones de encabezado. Esto efectivamente los hace parte del archivo de encabezado pero separa las declaraciones de cualquier definición.

Dado que son archivos de encabezado glorificados, debe tomar las mismas precauciones que tomaría con un archivo de encabezado normal, es decir, incluir protectores, etc.

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-ah-file-and-imp

Entre ellos hay uno fácil en el que crea un "simulado" método en el archivo .cpp, que llama a la función plantilla / clase con los diferentes tipos. Pegado del enlace:

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

Me acabo de dar cuenta de que tenía una segunda pregunta que parece no tener respuesta:

  

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

Es posible. Por ejemplo, consulte 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 de parámetro en sí, sino en qué expresiones que involucran ese tipo son legales. Por ejemplo, imagina que tienes:

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

Decir que T debe heredar de algo como:

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

no aporta nada porque la creación de instancias 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 () y t.bar (const char *) son expresiones válidas en un const T. Por ejemplo, este tipo hace 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;
};

¿Puso su definición de función de plantilla en un archivo cpp? Luego muévalo al encabezado e introdúzcalo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top