2011-02-02 11 views
20

Esta es una pregunta de seguimiento a an answer a Is it possible to typedef a pointer-to-extern-“C”-function type within a template?¿Por qué las plantillas no pueden estar dentro de bloques externos "C"?

Este código falla al compilar con g++, Visual C/C++, y Comeau C/C++ con básicamente el mismo mensaje de error:

#include <cstdlib> 

extern "C" { 
    static int do_stuff(int) { 
     return 3; 
    } 

    template <typename return_t_, typename arg1_t_> 
    struct test { 
     static void foo(return_t_ (*)(arg1_t_)) { } 
    }; 
} 

int main() 
{ 
    test<int, int>::foo(&do_stuff); 
    return EXIT_SUCCESS; 
} 

g ++ dice "error: plantilla con enlace C", Visual C/C++ emite el error de compilación C2894, y Comeau C/C++ dice "error: esta declaración puede no tener un enlace externo" C ".

La cosa es que todos están contentos con:

#include <cstdlib> 

extern "C" { 
    static int do_stuff(int) { 
     return 3; 
    } 

    struct test { 
     static void foo(int (*)(int)) { } 
    }; 
} 

int main() 
{ 
    test::foo(&do_stuff); 
    return EXIT_SUCCESS; 
} 

Sección 7.5, especificaciones de vinculación, del estándar de C++ afirma:

A C language linkage is ignored for the names of class members and the member function type of class member functions.

E incluso da el ejemplo:

extern "C" { 
    class X { 
     void mf(); // the name of the function mf and the member 
       // function's type have C++ language linkage 
     void mf2(void(*)()); // the name of the function mf2 has C++ language 
       // linkage; the parameter has type pointer to C function 
    }; 
} 

Si se permitieron plantillas en bloques externos "C", entonces las funciones miembro de las instancias tendrían C++ l inkage.

Por qué, entonces, qué capítulo 14, plantillas, del C++ 98 estado estándar:

A template name may have linkage (3.5). A template, a template explicit specialization (14.7.3), and a class template partial specialization shall not have C linkage.

¿Qué significa que una plantilla "puede" tener vinculación? ¿Qué es el enlace de la plantilla?

¿Por qué está explícitamente prohibido tener una plantilla con vinculación C, cuando una clase es correcta y todas las funciones miembro de instancias de la plantilla (el constructor predeterminado, el destructor y la sobrecarga del operador de asignación) tendrían un enlace C++?

+1

Ah, se encontró que la cláusula que prohibe plantillas de tener vinculación C! –

Respuesta

7

What does it mean that a template "may" have linkage? What is template linkage?

Todos los nombres o bien tienen vinculación externa, enlace interno, o no tienen ninguna vinculación (C++ 03 §3.5p2), pero esto no es lo mismo vinculación como enlace del lenguaje. (Confuso, lo sé. C++ 0x también cambia considerablemente las cosas con el enlace.se requiere) la vinculación externa para cualquier cosa usada como un argumento de plantilla:

void f() { 
    struct S {}; 
    vector<S> v; // Not allowed as S has internal linkage. 
} 

en cuenta que C++ tiene 98 "puede" en lo que usted ha citado de §14p4, pero C++ 03 elimina el "puede", como se plantillas no se pueden declarar en un contexto que les daría enlace interno:

void f() { 
    // Not allowed: 
    template<class T> 
    struct S {}; 
} 
-4

porque no hay plantillas en C

+10

No hay clases en C, sin embargo, está permitido que las declaraciones de clase (y las definiciones) aparezcan en un bloque "C" externo. ¿Por qué? –

3

Debido a que los nombres de función de plantilla tienen que ser decorado con información adicional y extern "C" convierte la decoración fuera. El propósito de extern "C" es poder declarar las funciones que se pueden llamar con el enlace C, que es algo que nunca funcionará obviamente con una función de plantilla.

+1

El ejemplo citado del Estándar dice que una clase se puede declarar en un bloque Extern "C" y sus funciones miembro se declaran con un enlace C++. Si se permitiera una plantilla, entonces sus funciones miembro también tendrían un enlace C++. Esa es la "información adicional" a la que creo que se refiere. Supongo que no entiendo cuál es la diferencia. –

+0

@Daniel, los nombres de clase no * necesitan * para decorarse, pero los nombres de las plantillas sí; de lo contrario, ¿cómo distinguiría el compilador entre 'plantilla ' y 'plantilla '? –

13

Las plantillas no son códigos reales, solo son pautas para el compilador sobre cómo generar el código una vez que se conocen los parámetros de la plantilla. Como tal, en realidad no existen hasta que intentes usarlos. No puede proporcionar enlaces a algo que no existe.

+1

¿Por qué el Estándar C++ permite explícitamente declarar clases dentro de un bloque Extern "C"? –

+2

@Daniel, las clases son concretas y no ambiguas. Aunque los métodos pueden ser inalcanzables desde C, los miembros de los datos aún pueden ser útiles. –

+2

Los miembros de datos no se destrozan y no tienen una convención de llamadas. La norma dice explícitamente que Extern "C" no se aplica a ellos. No veo cómo usarlos de C importa aquí. –

2

Debido extern C desactiva renombrado de nombres, que utilizan plantillas de

Para ver las plantillas que se implementan con el nombre mangling, compilar y descompilar:

#include <cassert> 

template <class C> 
C f(C i) { return i; } 

int main() { 
    f<int>(1); 
    f<double>(1.5); 
} 

con:

g++ -c -g -std=c++98 main.cpp 
objdump -Sr main.o 

La salida contiene:

int main() { 
    0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: 48 83 ec 10    sub $0x10,%rsp 
    f<int>(1); 
    8: bf 01 00 00 00   mov $0x1,%edi 
    d: e8 00 00 00 00   callq 12 <main+0x12> 
      e: R_X86_64_PC32 _Z1fIiET_S0_-0x4 
    f<double>(1.5); 
    12: 48 b8 00 00 00 00 00 movabs $0x3ff8000000000000,%rax 
    19: 00 f8 3f 
    1c: 48 89 45 f8    mov %rax,-0x8(%rbp) 
    20: f2 0f 10 45 f8   movsd -0x8(%rbp),%xmm0 
    25: e8 00 00 00 00   callq 2a <main+0x2a> 
      26: R_X86_64_PC32 _Z1fIdET_S0_-0x4 
} 
    2a: b8 00 00 00 00   mov $0x0,%eax 
    2f: c9      leaveq 
    30: c3      retq 

Nota cómo se pusieron a todos callq llamar nombres extraños como _Z1fIiET_S0_.

Lo mismo ocurre con otras funciones que dependen del cambio de nombre, p. Ej. sobrecarga de función.

Consulte también: https://stackoverflow.com/a/30526795/895245

Cuestiones relacionadas