c++ - programacion - generalizacion y especializacion en java
definición múltiple de especialización de plantilla cuando se usan objetos diferentes (3)
Cuando uso una plantilla especializada en diferentes archivos de objetos, aparece un error de "definición múltiple" al vincular. La única solución que encontré implica el uso de la función "en línea", pero parece una solución. ¿Cómo lo soluciono sin usar la palabra clave "en línea"? Si eso no es posible, ¿por qué?
Aquí está el código de ejemplo:
paulo@aeris:~/teste/cpp/redef$ cat hello.h
#ifndef TEMPLATE_H
#define TEMPLATE_H
#include <iostream>
template <class T>
class Hello
{
public:
void print_hello(T var);
};
template <class T>
void Hello<T>::print_hello(T var)
{
std::cout << "Hello generic function " << var << "/n";
}
template <> //inline
void Hello<int>::print_hello(int var)
{
std::cout << "Hello specialized function " << var << "/n";
}
#endif
paulo@aeris:~/teste/cpp/redef$ cat other.h
#include <iostream>
void other_func();
paulo@aeris:~/teste/cpp/redef$ cat other.c
#include "other.h"
#include "hello.h"
void other_func()
{
Hello<char> hc;
Hello<int> hi;
hc.print_hello(''a'');
hi.print_hello(1);
}
paulo@aeris:~/teste/cpp/redef$ cat main.c
#include "hello.h"
#include "other.h"
int main()
{
Hello<char> hc;
Hello<int> hi;
hc.print_hello(''a'');
hi.print_hello(1);
other_func();
return 0;
}
paulo@aeris:~/teste/cpp/redef$ cat Makefile
all:
g++ -c other.c -o other.o -Wall -Wextra
g++ main.c other.o -o main -Wall -Wextra
Finalmente:
paulo@aeris:~/teste/cpp/redef$ make
g++ -c other.c -o other.o -Wall -Wextra
g++ main.c other.o -o main -Wall -Wextra
other.o: In function `Hello<int>::print_hello(int)'':
other.c:(.text+0x0): multiple definition of `Hello<int>::print_hello(int)''
/tmp/cc0dZS9l.o:main.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
make: ** [all] Erro 1
Si elimino el comentario de "en línea" dentro de hello.h, el código se compilará y ejecutará, pero eso me parece una especie de "solución alternativa": ¿y si la función especializada es grande y se usa muchas veces? ¿Obtendré un gran binario? Hay alguna otra manera de hacer esto? Si es así, ¿cómo? Si no, ¿por qué?
Traté de buscar respuestas, pero todo lo que obtuve fue "usar en línea" sin más explicaciones.
Gracias
Ha instanciado explícitamente una plantilla en su encabezado ( void Hello<T>::print_hello(T var)
). Esto creará múltiples definiciones. Puedes resolverlo de dos maneras:
1) Haga su instanciación en línea.
2) Declare la instanciación en un encabezado y luego impleméntelo en un cpp.
Intuitivamente, cuando se especializa completamente en algo, ya no depende de un parámetro de plantilla, así que a menos que haga la especialización en línea, debe ponerlo en un archivo .cpp en lugar de .h o termina violando el una regla de definición como dice David. Tenga en cuenta que cuando se especializan parcialmente las plantillas, las especializaciones parciales todavía dependen de uno o más parámetros de plantilla, por lo que aún se incluyen en un archivo .h.
La palabra clave en inline
es más acerca de decirle al compilador que el símbolo estará presente en más de un archivo de objeto sin violar la Regla de una sola definición que sobre la alineación real, que el compilador puede decidir hacer o no hacer.
El problema que está viendo es que sin la línea, la función se compilará en todas las unidades de traducción que incluyan el encabezado, violando el ODR. Agregar en inline
existe el camino correcto a seguir. De lo contrario, puede reenviar declarar la especialización y proporcionarla en una sola unidad de traducción, como lo haría con cualquier otra función.