2010-02-08 12 views

Respuesta

11

El último parámetro de la plantilla for_each es un functor. Functor es algo que se puede "llamar" utilizando el operador () (posiblemente con argumentos). Por Defintion, hay dos tipos distintivos de funtores:

  1. funciones que no son miembros ordinarios son funtores.
  2. Los objetos del tipo de clase con el operador sobrecargado () (llamados objetos de función) también son funtores.

Ahora, si desea utilizar una función ordinaria como un funtor de for_each, se vería algo como lo siguiente

inline void do_something(int &i) { /* do something */ } 

int main() { 
    int array[10]; 
    std::for_each(array, array + 10, &do_something); 
} 

En este caso la plantilla for_each se instancia con argumentos [deducidas] <int *, void (*)(int &)> . Tenga en cuenta que el valor real del functor en este caso es el puntero a la función &do_something pasado como el argumento de la función. Desde el punto de vista de la función for_each, este es un valor de tiempo de ejecución. Y dado que es un valor de tiempo de ejecución, las llamadas al funtor no pueden incluirse. (Al igual que en general es imposible hacer una llamada en línea a través de un puntero de función).

Pero si usamos un objeto función en su lugar, el código podría ser de la siguiente manera

struct do_something { 
    void operator()(int &i) { /* do something */ } 
}; 

int main() { 
    int array[10]; 
    std::for_each(array, array + 10, do_something()); 
} 

En este caso la plantilla for_each se instancia con argumentos [] deducidas <int *, do_something>. Las llamadas al functor desde el interior for_each se dirigirán al do_something::operator(). El objetivo para la llamada es conocido y corregido en tiempo de compilación. Como la función de destino se conoce en tiempo de compilación, la llamada puede ser fácilmente inlineada.

En este último caso, por supuesto, también tenemos un valor de tiempo de ejecución pasado como argumento a for_each. Es una instancia [posiblemente "ficticia" temporal] de la clase do_something que creamos cuando llamamos al for_each. Pero este valor de tiempo de ejecución no tiene ningún efecto en el destino para la llamada (a menos que el operator() sea virtual), por lo que no afecta la alineación.

+0

Pero la definición completa de ':: std :: for_each' está disponible para el compilador. Para un compilador inteligente, debería ver que se está llamando con un argumento particular que resulta ser la dirección de una función que se declaró en línea. El compilador debería poder alinear la llamada de función tan bien como si fuera un método de clase. – Omnifarious

+2

@Omnifarious: en mi ejemplo, puede llamar a 'for_each' con diferentes funciones que tienen la firma' void (int &) 'y el compilador está obligado a usar la misma, una y única instanciación de' for_each': 'for_each AnT

+2

Por ejemplo (olvidarse de las plantillas), cuando tengo la función 'void foo (int)' en mi programa y la llamo varias veces como 'foo (1); foo (2); foo (3); 'Generalmente espero que el compilador genere un cuerpo de función para' foo' y ejecute el mismo cuerpo con diferentes argumentos: 1, 2 y 3. Si descubro que el compilador generó en cambio 3 cuerpos diferentes de 'foo' 'con constantes" en línea "1, 2 y 3, respectivamente, estaré desagradablemente sorprendido. Para el pequeño 'foo' que estaría bien (si está inline después de eso), pero para un' foo' más grande esto no es deseable. Lo que describes es esencialmente lo mismo. – AnT

2

Alinear solo significa reemplazar cada llamada a esa función con el cuerpo de esa función directamente.

Es una optimización para pequeñas funciones porque reduce la sobrecarga de saltar a una nueva función y luego regresar.

3

Significa que la definición de la función (código) puede copiarse y salvarte de una llamada a función (que se considera costosa en algunos sistemas). Piensa en el reemplazo macro.

4

En línea es el proceso que un compilador puede reemplazar una llamada a una función con el contenido de la función en sí. Requiere que el compilador sepa el contenido de la función cuando se está compilando.

El compilador a menudo no puede hacer esto si se pasa un puntero a la función.