2011-08-01 12 views
7

¿Para qué se utilizaría typedef int (&rifii) (int, int)?C++ Sintaxis/Semántica Pregunta: Referencia a la función y la palabra clave typedef

¿Cuál es el tipodef antes de esta "declaración"? quiero pensar en esto como

typedef (int (&rifii) (int, int)) [new name] 

pero el [nuevo nombre] no está allí como si lo hace

typedef int INTEGER; 

pregunta similar para la siguiente sintaxis:

typedef void (*PF)(); 

PF edit_ops[ ] = { &cut, &paste, &copy, &search }; 
PF file_ops[ ] = { &open, &append, & close, &write }; 

PF* button2 = edit_ops; 
PF* button3 = file_ops; 

button2[2](); 

Lo ¿El typedef lo permite? ¿Es por lo que es por lo que no tiene que escribir:

void (*PF)(); 
(void (*PF)()) edit_ops[ ] = { &cut, &paste, &copy, &search }; 
(void (*PF)()) file_ops[ ] = { &open, &append, & close, &write }; 

(void (*PF)())* button2 = edit_ops; 
(void (*PF)())* button3 = file_ops; 

Si es así qué sucedió a la segunda parte ([lo que quiere]) de la typedef como en:

typedef [what you have -- (FP)] [what you want] 

Aclaración sobre este asunto es muy apreciado.

+0

un posible duplicado de http://stackoverflow.com/questions/1591361/understanding-typedefs-for-function-pointers-in-c-examples -hints-and-tips-plea – vines

+0

La pregunta es similar, y miré los temas relacionados antes de publicar, sin embargo, mi pregunta era específica y no pude extrapolar una respuesta de las otras publicaciones. –

Respuesta

16

Typedef no funciona como typedef [type] [new name]. La parte [new name] no siempre viene al final.

Debería verlo de esta manera: si [some declaration] declara una variable, typedef [same declaration] definiría un tipo.

E.g.:

  • int x; declara una variable llamada x de tipo int ->typedef int x; define un tipo X que int.
  • struct { char c; } s; define una variable llamada s de algún tipo de estructura ->typedef struct { char c; } s; define tipo s para ser un tipo de estructura.
  • int *p; declara una variable llamada p de tipo puntero a int -> typedef int *p; define un tipo p como puntero a int.

Y también:

  • int A[]; declara una matriz de enteros llamada A ->typedef int A[]; declara un tipo A como una matriz de enteros.
  • int f(); declara una función llamada f ->typedef int f(); declara una función tipo f como devolver un int y no tomar argumentos.
  • int g(int); declara un nombre de función g ->typedef int g(int); declara una función tipo g como devolver un int y tomar uno int.

Como nota adicional: ¡tenga en cuenta que todos los argumentos de funciones vienen después del nuevo nombre! Como esos tipos también pueden ser complicados, puede haber mucho texto después del [nombre nuevo]. Lamentablemente, pero cierto.

Pero esos no son la función adecuada punteros todavía, solo tipos de funciones. No estoy seguro de que exista un tipo de función en C o C++, pero es útil como un paso intermedio en mi explicación.

Para crear un puntero de función real, tenemos que agregar '*' al nombre. Lo cual, por desgracia, tiene prioridad equivocada:

  • typedef int *pf(); declara un tipo PF función que devuelva un int *. Oops, eso no es lo que se pretendía.

a fin de utilizar() al grupo:

  • typedef int (*pf)(); declara un tipo PF puntero de función que devuelve un int y sin argumentos.
  • typedef int (&rf)(); declara un tipo de referencia de función rf como devolver un int y no tomar argumentos.

Veamos ahora en sus ejemplos y contestar sus preguntas:

typedef int (&rifii) (int, int); declara un tipo de referencia función rifii como devolver un int y teniendo dos argumentos int.

Y obviamente (?) button2[2](); llamará copy();.

sintaxis adecuada y sin typedefs es difícil escribir correctamente sin un compilador, y difícil de leer incluso con un compilador:

void (*edit_ops[])() = { &cut, &paste, &copy, &search }; 
void (*file_ops[])() = { &open, &append, & close, &write }; 

void (**button2)() = edit_ops; 
void (**button3)() = file_ops; 

button2[2](); 

Razón por la cual todo el mundo prefiere typedefs al utilizar punteros de función.

Al leer, encuentre el lugar para comenzar a leer. Lea todo lo que pueda a la derecha, pero observe la agrupación por(). Luego lea a la izquierda tanto como pueda, otra vez limitado por la agrupación(). Después de terminar todo dentro de(), comience con la lectura a la derecha, luego a la izquierda.

Aplicado a void (*edit_ops[])(), esto significa que

  1. edit_ops es (ir a la derecha)
  2. una serie (golpear el extremo del grupo, por lo que girar a la izquierda)
  3. de puntero (final de la agrupación)
  4. a una función de tomar (analizar el() a la derecha)
  5. no argume NTS (ir a la izquierda)
  6. devolver un vacío

Para los expertos: para que sea aún más complicado, los argumentos pueden tener nombres (que serán ignorados), por lo que incluso podría ser ¡difícil de encontrar por dónde empezar a analizar! P.ej. typedef int (*fp)(int x); es válido y lo mismo que typedef int (*fp)(int); Los nombres incluso pueden tener() alrededor de ellos: typedef int (*fp)(int (x)); Pero como hemos visto, los nombres de los argumentos pueden omitirse, por lo que se permite lo siguiente: typedef int (*fp)(int());. Este sigue siendo un puntero de función que toma una sola int y devuelve un int. En caso de que quiera hacer que su código sea realmente difícil de leer ...

+0

Su explicación está ayudando. Para aclaración: typedef void (* PF)(); declara un tipo (* PF) que se define como un puntero a función que toma 0 argumentos y no devuelve nada. Entonces ahora tenemos un tipo PF si podemos usar eso en nuestras expresiones (puede significar enunciados) como PF edit_ops [] = {. ..}. Sin definir el "nuevo tipo" usamos void (* edit_ops [])() = {...}. Esto dice que estamos creando una matriz de punteros de función que puede ser uno de ...? tipo de esta expresión es un puntero a la función? –

+0

@Matthew: Sí, 'void (* edit_ops []() = {...}; 'está definiendo una matriz de punteros de función e inicializa esta matriz con los valores' cut', 'paste',' copy', y 'search'. 'void (** button2)() = edit_ops;' declara un puntero al elemento cero-th de esa matriz. 'button2 [2]();' usa el tercer elemento de la matriz y llama a la función a la que apunta. Lo que sucede es 'copia'. – Sjoerd

+0

@Matthew: En su primera oración, 'typedef void (* PF)()' declara un tipo 'PF', * not *' (* PF) '. 'PF' ya es un puntero. La última declaración 'void (* x [])() = ...' declara 'x' como una matriz de punteros a función. –

-1

corregir: sorry first answer no inicializó el fcn ptr.

typedef int (& rifii) (int, int) le permite declarar punteros a función que devuelven un int por referencia y tomar dos ints como parámetros.

rifi x,y,z; 

int &ret_an_int_ref(int p1, int p2) { 
    static int retval=0; 
    if(p1 > p2) retval = p1*p2; 
    return retval; 
} 

    x = ret_an_int_ref; 
    y = ret_an_int_ref; 

int & an_int_ref = x(1,2); 
int & another_int_ref=y(3,4); 

z = x; 

z(1,2); // will give the same answer as x(1,2); 
+0

Entonces rifi ahora es un tipo? Y las variables x, y y z son de ese tipo? Y de acuerdo con Bjarne, devolver una referencia de una función es un pecado, entonces, ¿estoy asumiendo que nunca veré esto? –

+0

No puedo decir con 100% de certeza si rifi es un "tipo", ojalá un gurú pueda sonar. Actúa como un tipo, se puede pasar como un tipo, y probablemente se usa como un parámetro de plantilla. Lo más probable es que nunca vea esto, sin embargo, a veces, para tipos de datos complejos, es mejor devolverlo por ref. Y el operador = siempre debe devolver por ref, de modo que los enunciados tontos como A = A no causen un fallo seg. –

+0

La función no devuelve una referencia a int, pero es una referencia a una función que devuelve un int (simple). Su versión habría sido 'typedef int & (rifii) (int, int);' – Sjoerd

5

Este:

typedef int (&rifii) (int, int); 

Crea un typedef llamado rifii, que es una función que toma dos enteros y devuelve un entero. Esta es la sintaxis typedef para declarar la función typedefs. Así que si usted tiene una función:

int SomeFunc(int a, int b); 

se puede almacenar en el que typedef:

rifii varName = SomeFunc; 

y llamarlo más tarde:

varName(1, 3); 

por lo que si se declara una matriz de rifii, lo que tienes es una serie de referencias a funciones que todas tienen la misma firma. El typedef suyo PF es una función de puntero que no toma parámetros y no devuelve nada, por lo que una matriz de estos es una matriz de funciones que no toman parámetros y no devuelven nada.

Básicamente, debido a la rareza de la denominación de función C/C++, el nombre typedef (el nombre para el que está creando un typedef) va en el medio del tipo de función. Es extraño, pero te acostumbras.

Cuestiones relacionadas