2012-09-18 15 views
17

Desde el proyecto de C++ 11, 7.5 (párrafo 1).:¿Las funciones "C" externas son un tipo separado?

dos tipos de eventos de diferentes idioma vínculos son tipos distintos, incluso si son de otro modo idénticas.

Así que puedo hacer sobrecarga basado en vínculos de idioma:

extern "C" typedef void (*c_function)(); 
typedef void (*cpp_function)(); 

void call_fun(c_function f) 
{ 
} 
void call_fun(cpp_function f) 
{ 
} 

extern "C" void my_c() 
{ 
} 
void my_cpp() 
{ 
} 
int main() 
{ 
    call_fun(my_c); 
    call_fun(my_cpp); 
} 

Pero, con GCC 4.7.1 este código de ejemplo da los mensajes de error:

test.cpp: In function 'void call_fun(cpp_function)': 
test.cpp:7:6: error: redefinition of 'void call_fun(cpp_function)' 
test.cpp:4:6: error: 'void call_fun(c_function)' previously defined here 

Y con CLANG ++:

test.cpp:7:6: error: redefinition of 'call_fun' 
void call_fun(cpp_function f) 
    ^
test.cpp:4:6: note: previous definition is here 
void call_fun(c_function f) 
    ^

Ahora las preguntas:

  • ¿Mi comprensión de la norma es correcta? ¿Es este código válido?

  • ¿Alguien sabe si estos son errores en los compiladores o si intencionalmente lo hacen de esa manera por razones de compatibilidad?

+0

Sólo para que conste: el estándar de C++ 03 tiene exactamente la misma frase en el mismo párrafo, por lo que este no se trata de una característica de C++ 11 aún no admitida por los compiladores. – Gorpik

+0

Ver http://stackoverflow.com/a/10643935/1463922. Asegúrese de que las convenciones de llamadas de C y C++ coincidan. – PiotrNycz

Respuesta

8

Se trata de un error conocido en gcc, y registran que no es conforme, ya que este error bloquea el problema principal, "C++ 98 problemas de conformidad".

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=2316

Comprobar la fecha de creación.

Hay una discusión al final, sobre los aspectos prácticos de la introducción de una solución. Así que la respuesta a su última pregunta es "both": es un error y el error se ha dejado intencionalmente para compatibilidad.

Otros compiladores con el mismo problema pueden haber cometido el error de forma independiente, pero creo que es más probable que también sepan que es incorrecto, pero quieren ser compatibles con errores con gcc.

+0

Triky, porque realmente estoy usando punteros para funciones de plantilla convertidas en punteros a funciones "externas" C "'. No sé de ninguna manera para hacer una función de plantilla '' externa '', así que creo que mantendré mi código como está ahora ... – rodrigo

+0

Mmm, suena exasperante. Supongo que puedes hacerlo con (como máximo) una función contenedora C '' extern "por API C que usas, siempre que la función C-linkage tome un puntero de datos de usuario. Pasa de contrabando el puntero de la función de vinculación de C++ a la función de vinculación C guardándola en los datos del usuario y llamándola desde allí. "Si tienes dudas agrega más indirección", más o menos. –

+0

@Steve_Jessop: Gracias, tenía algo así en mente, pero eso rompe mi objetivo de cero gastos que perseguí cuando usé plantillas en lugar de un objeto de despachador con una función virtual y una función de miembro estático ... _D'oh! _ – rodrigo

10

El código es claramente válido. G ++ (y un número de otros compiladores) son un poco laxo (por decirlo suavemente) sobre la integración de la vinculación en el tipo.

+0

+1 Según la cotización que OP proporcionó, esto parece ser correcto, a menos que exista alguna esquina del estándar que agregue una excepción a dicha cita. De todos modos, conociendo a James creo que él sabe mejor y confío en su palabra al respecto:) –

+1

@Als El ejemplo clásico donde esto hace una diferencia: pasando una función miembro estática a 'pthread_create' (o' CreateThread'). De acuerdo con el estándar, esto es ilegal (ya que 'pthread_create' requiere un' extern "C" ', y un miembro no puede ser' extern "C" '), pero tanto g ++ como VC++ lo permiten. –

+0

Gracias. El caso es que tengo un código que confía en este comportamiento de GCC.Funciona, por supuesto, pero me hace un poco incómodo porque parece ser totalmente no portátil. Mi problema es si esta laxitud es intencional y, por lo tanto, puedo considerarla una "extensión GCC". – rodrigo

1

Por lo que vale la pena, este código también falla al compilar con la configuración predeterminada en VS2012:

(8) error C2084: function 'void call_fun(c_function)' already has a body 
(4) see previous definition of 'call_fun' 
(19) error C3861: 'call_fun': identifier not found 
(20) error C3861: 'call_fun': identifier not found 
+0

Pero el compilador en línea [Coumeau C++] (http://www.comeaucomputing.com/tryitout/) lo acepta sin previo aviso. – rodrigo

Cuestiones relacionadas