2012-01-23 12 views
5

Tengo un problema extraño. En Windows, con Visual Studio 2010 y también con el compilador Intel todo está vinculado como se esperaba. Pero cuando intento compilar mi código con CLang 3.0 en Linux, compila (y si solo uso un solo archivo CPP, también lo vincula y lo ejecuta) pero no enlaza.Linux C++: ¿Cómo usar apropiadamente las especializaciones de plantillas en múltiples archivos?

El mensaje es que hay múltiples definiciones de símbolos, que se refieren a instancias de plantilla. Por ejemplo, consideremos las dos líneas siguientes en un archivo de cabecera compartida a través de múltiples unidades de compilación:

template<class T> void myFunc(T in) { } 
template<> void myFunc<int>(int in) { } 

Ahora desde el enlazador Linux me gustaría tener algo en la línea de:

"xyz archivo": múltiple definición de "myFunc (int in)", definido por primera vez en "algún archivo".

Pero, ¿cómo evitaría eso? Como funciona en Windows, supongo que también debería funcionar en Linux.

Lo mismo aplica para los miembros de datos de plantilla estáticos, que son más o menos los mismos que los anteriores simplemente declaran una variable en lugar de una función. Preferiría que funcionara para miembros de datos de plantilla estáticos.

Si todo lo demás falla, supongo que todavía podía crear un archivo "MakeAll.cpp" que acaba incluye CPP hay, pero eso no suena como una solución deseable para mí ...

Gracias por ¡tu ayuda!

+0

¿Está utilizando #include guardias? –

+1

@SteveC el usuario indica que el código compila pero no enlaza. Los guardias incluirían desencadenar errores de compilación en lugar de errores de tiempo de enlace. –

Respuesta

8

En mi entendimiento, que son, de hecho, la definición de sus especializaciones de plantilla en múltiples ocasiones, y esto también te dará un error de compiladores de Windows.

En el archivo de cabecera que son definir una función mediante la provisión de un cuerpo: existirá

template<> void myFunc<int>(int in) { } 

Esta definición en múltiples unidades de compilación y el enlazador debe se quejan.

Las mismas reglas se aplican para su especialización de plantilla como para funciones que no son de plantilla ordinaria, puede coger inline o usar una declaración por separado y definición, poniendo

template<> void myFunc<int>(int in); 

en un encabezado y

template<> void myFunc<int>(int in) 
{ 
    // ... 
} 

en un archivo .cpp.

+0

No se queja en Windows. Intentaré lo más rápido posible;). El punto es que necesito miembros de datos de plantilla estáticos (ese es mi enfoque actual). ¿Y vienen con el mismo problema solo que no puedo alinearlos? – thesaint

+0

Esta respuesta es incompleta. Ver http://stackoverflow.com/questions/5453361/c-template-specialization-linker-error-multiple-definitions –

0

No tengo el estándar a mano ahora, pero creo que la especialización tiene que ser declarada inline.

+0

Lo intentaré, pero ¿qué haría con los miembros de la plantilla estática? Producen el mismo error pero no puedo alinearlos ... – thesaint

+1

@thesaint tendrá que mover las definiciones de los miembros de datos estáticos de * full speceializations * (es decir, independientemente de cualquier argumento de plantilla) a una sola unidad de traducción. Lo que sucede es que una especialización completa no es una plantilla, y al no ser una plantilla, no cumple las reglas de la plantilla. –

+0

¡El punto es que esto no es posible! Porque deben declararse en encabezados compartidos. Por lo general, puede anteponer una "estática" delante de la declaración de datos para hacerlos privados para cada unidad de compilación, pero esto no funciona para los datos de plantilla? Y esta es probablemente la razón por la cual el enlazador de MSVC ignora estos conflictos. Porque si no tengo forma de deshacerme de ellos en el código, el Enlazador hace un trabajo tonto si informa un error en lugar de una advertencia; al menos si no hay nada que pueda hacer al respecto? – thesaint

3

plantillas se crean instancias por el compilador, y es la responsabilidad de los compiladores para asegurarse de que sólo se definen una vez.

Cuando usted se especializa completamente una función, no es una plantilla de más (pero una función ordinaria), y es su responsabilidad de asegurarse de que no se multiplicará definido.

Hay muy poca diferencia entre estas funciones

template<> 
void f<int>(int x) 
{ } 

void f(int x) 
{ } 

cuando se trata de la regla de una definición.

Agregar inline ayuda en ambos casos.

+0

Bueno, tal vez es un error en CLang 3 entonces. ¿Tal vez también tienes una solución para miembros de datos de plantilla estáticos? Causan el mismo problema y no puedo alinearlos ... – thesaint

+0

Creo que Clang es correcto, pero en realidad no es un error para otros hacer que funcione de todos modos. :-) Y no creo que haya una solución para los miembros de los datos, aparte de dividir sus macros en dos partes, una para el encabezado y otra para la implementación. –

+0

de la docena de entradas de google principales en "especialización de plantillas de definición múltiple", ¡su respuesta fue la única que explica por qué! –

Cuestiones relacionadas