Ambiguïté possible avec des «C» externes, une surcharge et des pointeurs de fonction

Avec des fonctions normales, on peut écrire

extern "C" int Frotz(int); // in a header int Frotz(int x) { return x; } 

Avec les pointeurs de fonction, cependant, cela semble avoir été implémenté de manière incohérente entre les compilateurs.

 extern "C" int Klutz(int (*)(int), int); int Klutz(int (*fptr)(int), int x) { return (*fptr)(x); } 

Dans la déclaration, l’argument est aussi extern "C" . Dans la définition, la plupart des compilateurs semblent correspondre à ces fonctions et font de Klutz une fonction extern "C" . Les compilateurs Sun et Cray, toutefois, interprètent ces fonctions comme étant différentes, ce qui produit un int Klutz(int (*fptr)(int), int x) surchargé int Klutz(int (*fptr)(int), int x) , ce qui génère ensuite une erreur de temps de lien.

Bien que les sections 7.5.5 de C ++ 98 et C ++ 11 garantissent l’interprétation de Frotz , je ne peux pas dire si la norme est ambiguë sur le sharepoint savoir si la correspondance extern "C" doit avoir lieu avant ou après le contrôle de surcharge.

Klutz ci-dessus doit-il générer un symbole mutilé (C ++) ou un symbole extern "C" ?

EDIT 1

Je pourrais utiliser un typedef pour lever l’ambiguïté du pointeur de fonction sur ABI C ou C ++, mais je voudrais savoir si le code ici (a) définit Klutz comme ayant une liaison C ++, (b) le définit comme ayant une liaison C, ou (c ) est ambigu selon la norme, de sorte que les compilateurs sont libres de choisir comment l’interpréter.

EDIT 2

Cela semble être un problème connu, du moins par les compilateurs dotés de suiveurs de bogues interrogeables. Dans mes tests, GCC, Clang, Intel, MSVC, IBM XL, PathScale, PGI et Open64 ne parviennent pas à distinguer les types de fonctions identiques à l’exception du couplage de langue, comme le requirejs explicitement le standard (voir la section 7.5.1, citée dans la réponse acceptée). Résoudre ce problème casserait beaucoup de code existant et nécessiterait une modification de ABI. Je ne suis au courant d’aucun compilateur utilisant une convention d’appel différente pour le couplage de langage C à C ++.

  • Bug GCC : “Trouver des raisons de demander le retrait de cette fonctionnalité de la norme suivante est en quelque sorte pertinent ;-)” … “Et nous pourrions même choisir un WONTFIX officiel.”

  • Clang bug : “Je suis vraiment terrifié à l’idée de faire appliquer cette règle, car le faire correctement signifie intégrer le couplage linguistique au type canonique, ce qui va casser une tonne de code.”

C ABI et C ++ ABI ne sont pas garantis identiques. Ainsi, un pointeur de fonction extern "C" est d’un type différent d’un pointeur de fonction C ++. Vous avez besoin de quelque chose comme ça:

 extern "C" { typedef int (*KlutzFuncType)(int); int Klutz (KlutzFuncType, int); } int Klutz (KlutzFuncType fptr, int x) { return (*fptr)(x); } 

Il y a quelques discussions sur cette question ici .


Je n’ai qu’une copie du brouillon . À partir de 7.5p1:

Deux types de fonctions avec des liaisons linguistiques différentes sont des types distincts même s’ils sont par ailleurs identiques.

Mon interprétation de ceci est que le premier paramètre de votre premier Klutz a un type différent de celui du premier paramètre de votre deuxième Klutz et que, par conséquent, votre deuxième Klutz devrait avoir une liaison C ++.


Il existe des implémentations C ++ qui ne prennent pas en compte la liaison de langage pour les types de fonction, malgré ce que dit la norme. Dans l’extrait de code suivant, KlutzCxxFuncType fait référence à une fonction avec une liaison C ++, tandis que KlutzCFuncType fait référence à une fonction avec une liaison C.

 typedef int (*KlutzCxxFuncType)(int); extern "C" { typedef int (*KlutzCFuncType)(int); int Klutz (KlutzCFuncType, int); } int Klutz (KlutzCxxFuncType fptr, int x) { return (*fptr)(x); } int Klutz (KlutzCFuncType fptr, int x) { return (*fptr)(x); } 

Un compilateur qui ne distingue pas les types de fonction basés sur la liaison de langue générera une erreur de redéfinition sur ce code. Par exemple, g++ 4.7.2 émettra:

 prog.cpp: In function 'int Klutz(KlutzCFuncType, int)': prog.cpp:9:5: error: redefinition of 'int Klutz(KlutzCFuncType, int)' prog.cpp:8:5: error: 'int Klutz(KlutzCxxFuncType, int)' previously defined here