2009-03-16 17 views
28

Tengo una función declarada como tal:plantillas de C++, referencia indefinida

template <typename T> 
T read(); 

y definido de este modo:

template <typename T> 
T packetreader::read() { 
    offset += sizeof(T); 
    return *(T*)(buf+offset-sizeof(T)); 
} 

Sin embargo, cuando trato de usarlo en mi función main():

packetreader reader; 
reader.read<int>(); 

me sale el siguiente error de g ++:

g++ -o main main.o packet.o 
main.o: In function `main': 
main.cpp:(.text+0xcc): undefined reference to `int packetreader::read<int>()' 
collect2: ld returned 1 exit status 
make: *** [main] Error 1 

¿Alguien puede dirigirme en la dirección correcta?

+0

posible duplicado de [referencia indefinida a funcionar plantilla cuando se utiliza con una cuerda (CCG)] (http: // stackoverflow.com/questions/614233/undefined-reference-to-function-template-when-used-with-string-gcc) – outis

Respuesta

24

Debe utilizar la palabra clave export. Sin embargo, no creo que G ++ tenga el soporte adecuado, por lo que debe incluir la definición de la función de la plantilla en el encabezado para que la unidad de traducción pueda usarla. Esto se debe a que la 'versión' <int> de la plantilla no se ha creado, solo la 'versión' <typename T> '.

Una manera fácil es #include el archivo .cpp. Sin embargo, esto puede causar problemas, p. cuando otras funciones están en el archivo .cpp. También probablemente aumentará el tiempo de compilación.

una manera limpia es mover sus funciones de plantilla en su propio archivo .cpp, y que lo incluya en el encabezado o utilizar la palabra clave export y compilar por separado.

More information on why you should try and put template function definitions in its header file (and ignore export altogether).

+0

¿Sería una buena idea para mí mover mi código packet.cpp en packet.h y cambiarle el nombre a algo así como "packet.hpp" como a menudo he visto usado en boost –

+1

@Daniel, solo si todas sus funciones son funciones de plantilla. De lo contrario, puede salirse con la mudanza de algunas de sus funciones y mantener el archivo .cpp. – strager

4

La mejor práctica con funciones de plantilla es definirlos en los archivos de cabecera. Se crean en tiempo de compilación, por lo que el compilador debe tener una definición para hacerlo.

Cuando export para las plantillas serían más compatibles, este no sería el caso, pero en este momento todavía difícilmente se puede utilizar.

+0

No recomiendo usar 'export'. De acuerdo con http://www.parashift.com/c++faq-lite/templates.html#faq-35.14, ha sido votado fuera del estándar C++ 0x. – uckelman

12

El problema es que una plantilla de función no es una función. Es una plantilla para crear funciones según sea necesario.

Para que una plantilla funcione, el compilador necesita intuitivamente dos elementos de información: la plantilla misma y el tipo que se debe sustituir en ella. Esto es diferente de una llamada a función, que el compilador puede generar tan pronto como sepa que la función existe. No necesita saber qué hace la función, solo que se ve como void Frobnicate(int, float), o cualquiera que sea su firma.

Cuando declara la plantilla de función sin definirla, solo le está diciendo al compilador que existe dicha plantilla, pero no lo que parece. Eso no es suficiente para que el compilador pueda instanciarlo, también debe poder ver la definición completa. La solución habitual es poner toda la plantilla en un encabezado que se puede incluir cuando sea necesario.

0

¿Su plantilla de compatibilidad de compiladores está separada de la compilación?

Como sé que la práctica común es declarar y poner en práctica las funciones de plantilla en el archivo de cabecera

+0

Comeau, ¿verdad? Y la versión moderna de MSVC * podría * pero no lo he comprobado. – vava

+0

El último VS2008 aún no admite la palabra clave export. parece que los chicos de MS reservaron esta palabra clave para soporte futuro: advertencia C4237: la palabra clave 'exportar' aún no es compatible, pero está reservada para uso futuro –