web-dev-qa-db-fra.com

syntaxe typedef avec les pointeurs de fonctions membres

selon MSDN, la syntaxe typedef est la suivante:

synonyme de déclaration de type typedef;

Très facile:

typedef int MY_INT;

Mais comment diable les typedefs membre-fonction-pointeur sont-ils conformes à cette règle?

typedef int (MyClass::*MyTypedef)( int);

100% de confusion - le synonyme (MyTypedef) est au milieu?

Quelqu'un peut-il expliquer s'il vous plaît quelles sont les étapes logiques à suivre pour passer du format de syntaxe très facile à comprendre de MSDN à la syntaxe inverse/aléatoire/avant/dernier/mixte d'Aboves Typedef?

* éditer merci pour toutes les réponses rapides (et l'embellissement de mon post) :)

21
muxmux

le synonyme (MyTypedef) est au milieu ??

Ce n'est pas au milieu. Oubliez juste membre-fonction pendant un moment, voyez comment un pointeur de fonction est défini:

int (*FuncPtr)(int);

Et voici comment vous le typeriez:

typedef int (*FuncPtr)(int); 

Simple! La seule différence est que, dans le typedef, FuncPtr devient un type , alors que dans la déclaration du pointeur, FuncPtr est une variable

De même,

int (MyClass::*MyTypedef)( int); //MyTypedef is a variable

Et le typedef comme:

typedef int (MyClass::*MyTypedef)( int); //MyTypedef is a type!
35
Nawaz

Il est intéressant de noter que, à partir de C++ 11, vous pourriez écrire cette expression sous la forme d'une instruction using plus lisible:

using MyTypedef = int (MyClass::*)(int);
14
kfsone

Comment définissez-vous un pointeur sur une fonction membre? Comme ça:

int (A::*variableName)(int);

Pour en faire un typedef, ajoutez simplement un typedef:

typedef int (A::*typedefName)(int);
10
ybungalobill

Le principe de déclaration en C++ est qu’ils imitent l’utilisation. Si vous souhaitez utiliser un pointeur sur la fonction membre pmf, vous écrirez:

(myVar.*pmf)(arg);

donc pour définir un typedef, écrivez:

typedef int (MyClass::*pmf)(int);

en ajoutant le type de retour en tête, en remplaçant la variable par le type et les arguments par leur type.

4
AProgrammer

Je sais que vous avez déjà reçu votre réponse, mais je veux partager ceci - c'est pratique: http://www.cdecl.org . C'est une déclaration C/C++ <-> traducteur anglais. Il suffit de taper

déclarer x en tant que pointeur sur un membre de classe A fonction (int) retournant char

et vous obtenez char (A::*x)(int ). Ou jouez avec la déclaration et voyez si vous obtenez ce que vous voulez. 

4
davka

La syntaxe d'utilisation du pointeur de fonction de membre doit (supposer que a est une instance de la classe A):

  • dans la déclaration, utilisez "A ::" comme préfixe
  • quand l'utiliser, utilisez "a." comme préfixe

Ci-dessous, un exemple de jouet. Tu peux jouer avec.

#include <stdio.h>
#include <stdlib.h>
class A;
typedef int (A::*F)(double);

class A {
 public:
  int funcDouble(double x) { return (int)(x * 2.0); }
  int funcTriple(double x) { return (int)(x * 3.0); }

  void set(int a) {
    if (a == 2) {
      this->f_ = &A::funcDouble;
    } else if (a == 3) {
      this->f_ = &A::funcTriple;
    } else {
      this->f_ = NULL;
    }
  }

 public:
  F f_;
};
int main(int argc, char *argv[]) {
  A a;
  a.set(2);
  F f = &A::funcDouble;
  printf("double of 1 = %d\n", (a.*f)(1));

  // Below is equivalent to:
  // F f2 = a.f_;
  // printf("double of 1 = %d\n", (a.*f2)(1));
  printf("double of 1 = %d\n", (a.*(a.f_))(1));

  a.set(3);
  printf("triple of 1 = %d\n", (a.*(a.f_))(1));

  return 0;
}
2
zhanxw

La page à laquelle vous faites référence est probablement " typedef Specifier ". La syntaxe simpliste "typedef type-declaration synonim;" n’est qu’un des nombreux moyens d’utiliser typedef. Il n'y a (probablement) pas de manière simple et concise de décrire comment typedef peut être utilisé. C’est à quoi sert la page " Typedef Declarations " MSDN.

Vous remarquerez sur cette page quelque chose comme:

declaration: 
    declaration-specifiers init-declarator-list opt ; 
declaration-specifiers: 
    storage-class-specifier declaration-specifiers opt 
    type-specifier declaration-specifiers opt
    type-qualifier declaration-specifiers opt 
storage-class-specifier: 
    typedef

Plus de détails sur quels spécificateurs de déclaration et init-declarator-list peuvent être trouvés ici .

C'est un moyen rigoureux de comprendre tous les usages possibles de "typedef".

Ce que cette page dit fondamentalement, c'est que "typedef" peut être utilisé avant la plupart des déclarations valides.

1
Nick

Une fois, j’ai lu une bonne explication (mais elle provient de Expect C Programming so I ymmv):

En fait, une typedef a exactement le même format que En tant que déclaration de variable, Uniquement avec ce mot clé supplémentaire pour vous renvoyer .

Comme une typedef ressemble exactement à une déclaration de variable , Elle est lue Exactement comme une déclaration. Au lieu de la déclaration Disant: "ce nom fait référence à une variable du type indiqué," le mot clé Typedef ne crée pas de variable , mais force la déclaration à dire "ce nom est un synonyme du type indiqué".

Donc là vous l'avez. Imaginez que vous déclariez une variable, collez typedef avant et voilà, vous avez un nouveau type. Les explications MSDN sont un sac mélangé: j'ai vraiment lu celles qui sont dieu et celles qui sont vraiment mauvaises.

1
cnicutar

Il sera plus facile de comprendre quand vous commencez à penser comme ceci:

Chaque fois que vous voyez une fonction comme celle-ci:

TYPE foo(int arg1, int arg2);

Vous dites que le type de foo est TYPE. Donc, le type de

int get_next_prime();

est int.

Vous pouvez voir cela lorsque vous passez un pointeur de fonction en tant qu'argument à une fonction:

void register_callback(void (*ptr)(int));

Dans ce cas, vous transmettez une fonction de type void en tant qu'argument.

Maintenant, quand vous voyez quelque chose comme ça:

typedef int (A::*typedefName)(int);

vous dites simplement que la variable (A :: * typedefName) (int) (ce n'est qu'une chose, et non deux, puisqu'il s'agit d'une déclaration de pointeur de fonction) est en fait de type int. À partir de ce moment, le compilateur interprétera A :: * typedefName comme une fonction de type int, c'est-à-dire qu'il renvoie une valeur int.

J'espère que cela rend moins déroutant.

0