pointeur vers la fonction de membre de type incomplet

Je ne comprends pas pourquoi l'ajout d'une déclaration forward pour une classe change la taille de son pointeur en type de membre

#include 
using namespace std;

int main()
{
    //struct CL;
    //cout<<<<

sortie VS2013:
4

Mais si je décommente les deux premières lignes de main (), alors la sortie est différente:
16
16

Ainsi, seul un simple ajout d'une déclaration forward avant une définition de struct CL augmente la taille d'un pointeur vers un membre de CL. Pourquoi? Je sais qu'une taille de pointeur de fonction membre dépend de la structure d'un type (par exemple, les fonctions virtuelles et les classes de base peuvent l'augmenter), mais pourquoi l'opérateur sizeof peut-il être appliqué à un pointeur sur un type incomplet? Ou ça ne peut pas? Je ne l'ai pas trouvé dans la norme

0
struct CL {} est définitivement une classe locale dans la fonction. Pas sûr de struct CL; Quoi qu'il en soit, cela ressemble à un bug de msvc
ajouté l'auteur Dieter Lücking, source
@dyp Est-ce une autre raison de détester msvc?
ajouté l'auteur Dieter Lücking, source
@ DieterLücking struct CL; est une déclaration directe d'une classe locale dans ce cas, voir [basic.scope.pdecl] p7.1
ajouté l'auteur dyp, source
ajouté l'auteur dyp, source
@ DieterLücking C'est une autre raison de le configurer correctement;) Tout comme -Wall -Wextra -pedantic -std = c ++ ?? en g ++, vous devez désactiver les extensions de langage en cl, éventuellement désactiver le pliage comdat et forcez-le à utiliser la même taille pour tous les pointeurs membres.
ajouté l'auteur dyp, source

1 Réponses

Le compilateur MSVC utilise différentes tailles pour les pointeurs vers les fonctions membres en tant qu'optimisation. Cette optimisation viole la norme. Félicitations à Igor Tandetnik mentionnant reinterpret_cast dans a Poste de formulaire MSDN , [expr.reinterpret.cast] p10

Une prvalue de type "pointeur sur membre de X de type T1 " peut être   explicitement converti en prvalue d'un type différent "pointeur vers   membre de Y de type T2 "si T1 et T2 sont les deux types de fonctions   ou les deux types d'objet. La valeur du pointeur de membre null est convertie en   la valeur de pointeur de membre null du type de destination. Le résultat de   cette conversion est non spécifiée, sauf dans les cas suivants:

     
      
  • conversion d'un prvalue de type "pointeur en fonction membre" en un pointeur différent du type de fonction membre et retour à son original   type renvoie le pointeur d'origine à la valeur du membre.
  •   

Il y a donc une garantie d'aller-retour, ce qui force les implémentations conformes à utiliser la même taille pour tous les types de fonctions pointeur à membre.


L'optimisation MSVC est effectuée si le /vmb commutateur est défini. Dans le cas d'un héritage unique, le pointeur optimisé vers la fonction membre ne nécessite qu'un stockage void * , voir The Old New Thing: Les pointeurs vers les fonctions membres sont des animaux très étranges .

Si vous déclarez uniquement le type CL et formez ensuite une fonction pointeur vers membre, l'optimisation est, je l'espère, désactivée (je n'ai malheureusement trouvé aucune documentation à ce sujet). Sinon, vous risquez d'obtenir des tailles incohérentes avant et après la définition de CL .

En passant, vous pouvez obtenir des tailles incohérentes pour les énumérations dans VS2010, si vous les déclarez en avant sans spécifier un type sous-jacent et plus tard définissez explicitement le type sous-jacent pour la définition de l'énumération. Cela fonctionne uniquement avec les extensions de langue activées.

0
ajouté
Il y a aussi un pragma qui prétend que vous devez définir la classe avant de pouvoir créer un pointeur vers un membre. Mais ce n'est pas vrai au moins dans VS2013 ..
ajouté l'auteur dyp, source