2010-07-27 27 views
5

El nombre de una plantilla tiene un enlace (3.5). Una plantilla de función no miembro puede tener un enlace interno; cualquier otro nombre de plantilla tendrá un enlace externo. Las entidades generadas a partir de una plantilla con enlaces internos son distintas de todas las entidades generadas en otras unidades de traducción.plantilla ¿Vínculo externo? ¿Alguien puede explicar esto?

que sé sobre la vinculación externa usando la palabra clave

extern "C" 

EX:

extern "C" { template<class T> class X { }; } 

pero dio formulario no debe tener una vinculación C

lo que realmente significa para la declaración anterior?

¿alguien puede explicar esto?

+5

Acabo de notar que ha agregado una recompensa por la pregunta. Lo cual me parece extraño ya que considero que la respuesta que proporcioné es correcta y completa. ¿Qué es lo que todavía no entiendes? - He notado que también eliminó la parte inicial de la pregunta, haciendo que la mayoría de la respuesta sea inútil ... Debe considerar agregar comentarios o una pregunta diferente si todavía tiene dudas. Cambiar la pregunta no ayuda a nadie: las personas que ya han respondido no reciben notificaciones, las personas que navegan por las q & a estarán desconcertadas por las respuestas que no están relacionadas ... –

+0

Volvió a la versión antes de la eliminación, para que tenga más sentido . – Suma

+0

@David: Parece que BE Student está interesado en dar puntos específicamente al USUARIO. –

Respuesta

2

extern "C" se usa para cambiar el nombre del símbolo de la función C++ para usarlos desde un programa C.

En C++, el prototipo de función está "codificado" en el nombre del símbolo, este es un requisito para la sobrecarga. Pero en C, no tiene una función de este tipo.

extern "C" permiten llamar a la función C++ desde un programa en C.

extern "C" no es lo que está buscando.

¿Podría explicar qué quiere hacer?

+0

@Apatrice: Necesito la explicación del punto anterior –

+0

Ver http://en.wikipedia.org/wiki/Name_mangling#Handling_of_C_symbols_when_linking_from_C.2B.2B –

7

Con solo leer detenidamente la cita que escribió, notará que, excepto las plantillas de funciones que no son miembros que pueden tener enlaces internos, todas las otras plantillas tienen enlaces externos. No es necesario agregar palabras clave, ni palabras clave se pueden agregar allí.

la descripción de lo medios de unión está en §3.5/2, en particular enlazado externo se define como:

Cuando un nombre ha enlazado externo, la entidad que denota puede denominar de nombres desde ámbitos de otras unidades de traducción o desde otros ámbitos de la misma unidad de traducción.

Para forzar la vinculación interna de una función no miembro de la plantilla se puede utilizar la palabra clave static, pero no se puede hacer lo mismo con otras plantillas:

template <typename T> 
static void foo(T) {} 

Tenga en cuenta que se puede lograr un efecto similar de algún modo como enlace interno mediante el uso de espacios de nombres anónimos.

vinculación interna: § 3.5/2

Cuando un nombre tiene enlace interno, la entidad que denota puede denominar de nombres de otros ámbitos de la misma unidad de traducción.

Tenga en cuenta que la diferencia es que no se puede derivar desde otras unidades de traducción.

namespace { 
    template <typename T> 
    class test {}; 
} 

Mientras que el espacio de nombres sin nombre no hace al enlace interno, se asegura que no habrá ningún conflicto de nombres, ya que será en un único espacio de nombres. Esta singularidad garantiza que el código no sea accesible desde otras unidades de traducción. espacios de nombres Sin nombre se consideran ser una mejor alternativa a la static palabra clave §7.3.1.1/2

El uso de la palabra clave estática está en desuso al declarar objetos en un espacio de nombres alcance (véase el anexo D); el espacio de nombres sin nombre, ofrece una alternativa superior

Por otro lado, cuando se dice que:

sabe acerca de la vinculación externa usando la palabra clave extern "C"

Usted no lo hace. extern "C" no es una solicitud de vinculación externa. Vuelve a leer la especificación. extern "C" es una especificación de vinculación y le indica al compilador que use una vinculación de estilo "C" dentro del bloque para interactuar con el código C o bibliotecas que ya funcionan de esa manera, como dlopen y familia. Esto se describe en §7.5

2

La respuesta a la pregunta actualizada es, como ya dije en la respuesta que se aplica a la pregunta original, que está entendiendo mal lo que significa extern "C".

La secuencia extern "X" le permite cambiar el idioma vinculación de la siguiente función o bloque de lenguaje X. Se no se media vinculación externa, por lo que su premisa original:

que sé de vinculación externa usando la palabra clave extern "C"

es falsa. Tú no sabes lo que significa. Consulte 7.5 en el estándar. La vinculación del lenguaje afecta la forma en que el compilador procesa los parámetros y si aplica (y potencialmente cómo) el nombre de los nombres a los símbolos.

Dejando a un lado su insistencia en ese error en particular, el compilador se queja de su código porque no es válido de acuerdo con la norma. En particular §14 [temp]/4:

El nombre de una plantilla tiene un enlace (3.5). Una plantilla de función no miembro puede tener un enlace interno; cualquier otro nombre de plantilla tendrá un enlace externo. Las entidades generadas a partir de una plantilla con enlaces internos son distintas de todas las entidades generadas en otras unidades de traducción. Una plantilla, una especialización explícita de plantilla (14.7.3) o una especialización parcial de plantilla de clase no deben tener el enlace C. Si el enlace de uno de estos es algo distinto de C o C++, el comportamiento está definido por la implementación. Las definiciones de plantilla obedecerán a la regla de una definición (3.2).[Nota:. Argumentos por defecto para plantillas de función y de las funciones miembro de plantillas de clase se consideran las definiciones con el fin de instancias de plantilla (14.5) y también deben obedecer la regla de una definición]

Realmente creo que antes de intentar evalúe cómo los diferentes compiladores cumplen con el estándar; debe tomarse su tiempo para comprender el estándar. Es bastante bueno tener preguntas, y hay personas que hacen un esfuerzo por responderlas. Demostrar que ha leído las respuestas e intentado comprender lo que significan es solo un signo de respeto. ¿Qué parte del último párrafo de la respuesta anterior here no está clara? ¿Lo leíste? ¿Lo entendiste? Si no lo hizo, ¿por qué no preguntó en un comentario sobre la respuesta?

23

extern "C" declara que algo tiene Enlace de lenguaje C. Esto es diferente de enlace externo y enlace interno. Por defecto, todo en un programa C++ tiene un enlace de lenguaje C++, aunque puede reiterarlo especificando extern "C++".

enlace externo significa que el nombre es visible para otros archivos fuente compilados por separado, suponiendo que incluya los encabezados correctos o proporcione las declaraciones correctas. Esto es lo que le permite definir una función foo en a.cpp, y llamarla desde b.cpp. La mayoría de los nombres en el ámbito del espacio de nombres en un programa C++ tienen enlaces externos. Las excepciones son las que tienen enlace interno, y las que tienen sin enlace. Puede marcar explícitamente algo como que tiene un enlace externo especificando extern. Esto es distinto de extern "C".

enlace interno significa que el nombre es exclusivo de la unidad de compilación actual y no puede acceder a la variable o función desde otro archivo de origen. Las variables de ámbito de archivo y las funciones declaradas static tienen un enlace interno. Además, las variables enteras const en el ámbito del espacio de nombres que se inicializan con una expresión constante tienen un enlace interno por defecto, aunque puede anularlo con un extern explícito.

Finalmente, las variables locales y las clases tienen sin enlace. Los nombres son locales para la función en la que están declarados y no se puede acceder desde fuera de esa función. Puede usar extern para indicar que realmente desea acceder a una variable en el ámbito del espacio de nombres.

Las plantillas no se pueden definir en el ámbito local, pero pueden tener un enlace interno o externo.

int i; // namespace scope variable has external linkage 
extern int j; // explicitly mark j with external linkage 
static int k; // k has internal linkage 
int const n=42; // internal linkage 
extern int const m=99; // external linkage 

void foo(); // foo has external linkage; it may be defined in this source file or another 
extern void foo(); // explicitly mark foo with external linkage 
static void bar(); // bar has internal linkage, and must be defined in this source file 

void foo(){} // definition of foo, visible from other source files 
void bar(){} // definition of bar, not visible from other source files (internal linkage) 

static void baz(){} // declare and define baz with internal linkage 

template<typename T> void foobar(){} // foobar has external linkage 
template<typename T> 
static void foobaz(){} // foobaz has internal linkage 

void wibble() 
{ 
    int i; // local, no linkage 
    extern int i; // references i, declared above with external linkage 
} 

extern "C" 
{ 
    int i2; // namespace scope variable has external linkage, and "C" linkage 
    extern int j2; // explicitly mark j2 with external linkage and "C" linkage 
    static int k2; // k2 has internal linkage and "C" linkage 
    int const n2=42; // internal linkage and "C" linkage 
    extern int const m2=99; // external linkage and "C" linkage 

    void foo2(); // foo2 has external linkage and "C" linkage 
    static void bar2(); // bar2 has internal linkage and "C" linkage 

    void foo2(){} // definition of foo2, still with external linkage and "C" linkage 
    void bar2(){} // definition of bar2, still with internal linkage and "C" linkage 

    static void baz(){} // declare and define baz with internal linkage 
} 

El mensaje de error es correcto --- plantillas no pueden tener extern "C" vinculación.

En el nivel básico, las plantillas no pueden tener el enlace extern "C" porque no son compatibles con C. En particular, una plantilla no solo define una sola clase o función, sino una familia de clases o funciones que comparten el mismo nombre , pero se distinguen por sus parámetros de plantilla.

Solo se puede declarar una función con un nombre extern "C". Esto tiene sentido cuando piensas en el cambio de nombre --- en C, una función foo se llama normalmente foo o _foo en la tabla de símbolos.En C++ puede haber muchas sobrecargas de foo, por lo que la firma se incorpora al nombre "destrozado" en la tabla de símbolos, y puede obtener $3fooV o foo$void o alguna otra cosa para distinguir foo(void) de foo(int) y así sucesivamente. En C++, la única sobrecarga que está marcada extern "C" se destroza de acuerdo con el esquema C para la plataforma determinada, mientras que las otras sobrecargas mantienen su nombre normal.

Declarar una plantilla extern "C" requeriría que todos los ejemplificaciones ser extern "C", que de este modo contradice el "sólo una función con un nombre dado puede ser extern "C"" regla.

Aunque C no tiene nombre para struct s, solo puede haber un struct con un nombre de pila. La prohibición de extern "C" para plantillas de clase también tiene sentido --- una plantilla define una familia de clases con el mismo nombre, ¿cuál corresponde a la C struct?

Cuestiones relacionadas