2011-02-01 7 views
8

Quiero agregar un typedef público a una plantilla para un puntero a una función que toma un argumento que usa un enlace de lenguaje "C".¿Es posible escribir un tipo de función de puntero a externo? "C" dentro de una plantilla?

me trataron:

extern "C" { 
    template <typename return_t_, typename arg1_t_> 
    struct test 
    { 
     typedef return_t_ (*C_fun1_t)(arg1_t_); 
    }; 
} 

Y:

template <typename return_t_, typename arg1_t_> 
struct test 
{ 
    extern "C" { 
     typedef return_t_ (*C_fun1_t)(arg1_t_); 
    } 
}; 

Y:

template <typename return_t_, typename arg1_t_> 
struct test 
{ 
    extern "C" typedef return_t_ (*C_fun1_t)(arg1_t_); 
}; 

sin éxito.

¿Lo que intento lograr es posible?

+1

¿No es esto lo que hace que toda la C "externa" pueda usar una convención de llamadas diferente "una de esas cosas molestas que tienes que explicar pero que seguramente nunca pasará? Los tipos de puntero a función no distinguen entre los dos, porque 'extern" C "' no es parte del sistema de tipo, es un especificador de enlace. Esto significa que las llamadas a través del puntero creado * desde C++ * funcionarán independientemente de si la referencia del puntero es 'extern' C "' o no. Son llamadas realizadas desde C que pueden fallar, pero el sistema de tipos no lo comprueba. –

+3

@Steve: It * is * parte del sistema de tipo; C++ 03 §7.5p1: "Dos tipos de funciones con enlaces de idiomas diferentes son tipos distintos, incluso si son idénticos". §5.2.2p1: "Llamar a una función a través de una expresión cuyo tipo de función tiene un enlace de lenguaje que es diferente del enlace de lenguaje del tipo de función de la definición de la función llamada no está definida". –

+0

@Fred: oh, OK. Lo siento, no estoy seguro de dónde recogí esa información incorrecta, entonces. Además, si declaro una función externa "C" que toma un puntero a la función como parámetro, ¿toma una función "C" o una función "C++"? Porque g ++ felizmente me permite usar cualquiera de los dos con '-pedantic'. –

Respuesta

9

C++ 03, §7.5p4:

A linkage-specification shall occur only in namespace scope. … A C language linkage is ignored for the names of class members and the member function type of class member functions.

Por desgracia, simplemente no puede hacer esto en C++ actual. Este texto no se modifica en el último borrador de C++ 0x, pero "template typedefs" puede ser capaz de lograrlo.

+0

¿Dónde puedo obtener más información sobre "template typedefs"? –

+0

@DanielTrebbien: "Alias ​​de plantilla" parece ser el nuevo nombre; §14.5.7 en N3225 más varios documentos. –

+0

Y no, los alias de plantilla no resuelven este problema. El enlace C no se puede aplicar a las plantillas, incluidos los alias de tipo de plantilla. – bames53

1

Considere typedef de un boost::function o los objetos de la función STL ... tampoco puede definir una plantilla dentro de un bloque externo "C" por algunas razones bastante obvias si lo piensa.

+0

@Fred: Cuando coloco la definición de la plantilla dentro de un bloque externo "C", g ++ 4.5.0 emite el error "plantilla con enlace C". –

+0

esto puede ser específico del compilador entonces ... aquí está mi fuente http://msdn.microsoft.com/en-us/library/95bhc9c2.aspx – AJG85

+0

@DanielTrebbien: No hay nada en el estándar, que pueda ver (pero especialmente mirando en §7.5), que los excluye, pero parece que todos los compiladores los rechazan. (Esto tiene sentido, ya que sería ineficaz dado lo que cité en mi respuesta, pero eso es lo mismo que estrictamente no permitido.) –

0

Todo parece funcionar bien para mí si simplemente omito el extern "C" de su typedef. Es decir, los siguientes recopila, enlaces, y se ejecuta sin advertencias, errores o problemas:

foo.c:

#include <stdio.h> 
int foo(int x) { 
    return printf("%x\n", x); 
} 

test.cpp:

extern "C" int foo(int); 

template <typename return_t_, typename arg1_t_> 
struct test 
{ 
    typedef return_t_ (*C_fun1_t)(arg1_t_); 
    C_fun1_t myFn; 
}; 

int main() { 
    test<int, int> t; 
    t.myFn = foo; 
    return t.myFn(5); 
} 

Para los gurús de C++: No conozco los puntos más finos de lo que distingue el enlace C de C++. ¿Hay algún problema oculto que no aparezca en un ejemplo simple como este?

+1

Esto funciona con g ++ debido a un conocido problema (ver, por ejemplo, http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29038), pero Comeau C/C++ 4.3.10.1 emite el error "error: un valor de tipo 'int (\ *) (int) C 'no se puede asignar a una entidad de tipo' int (\ *) (int) '" –

+0

Estoy usando g ++ 4.4.3. – Karmastan

Cuestiones relacionadas