2011-11-10 18 views
11
int func(int x){return x;} 
... 
std::function<int(int)> x = std::bind(func, std::placeholders::_1); 
x(123); 
  1. ¿Se x(123) realidad llamar a la operator() del funtor, que genera std::function que a su vez llama a la operator() del funtor, que genera std::bind que se pide por último func? ¿Esto se optimiza en algo tan óptimo como llamar al func(123)?
  2. ¿Dónde vive el functor que genera std::bind? ¿En qué alcance? ¿Y cómo lo llama std::bind? (puede haber colisiones de nombres)
  3. ¿Pueden las lambdas reemplazar todos los usos de std::bind?
  4. ¿Es std::bind tan óptimo como implementarlo como un lambda?
  5. ¿Qué pasa con la sintaxis del argumento de plantilla de std::function? ¿Cómo se analiza y cómo puedo usar esa sintaxis de argumento de la plantilla en otro lugar?
+2

Para 2. usted podría estar interesado en http://www.artima.com/cppsource/type_erasure.html – Flexo

+4

Una pregunta a la vez, por favor. Cada publicación SO es una pregunta. –

+0

Esto es más un conjunto de preguntas que una pregunta concreta, y van desde la sintaxis (para el argumento de 'function <>') al comportamiento (¿dónde se produce el resultado de bind live? ¿Puede lambda sustituirlas?) El rendimiento (¿Está optimizado?) –

Respuesta

16

¿Tiene x (123) en realidad llamar al operador() de la cual funtor std :: function generated que a su vez llama al operador() del functor que std :: bind generado que finalmente llama func? ¿Esto se optimiza en algo tan óptimo como llamar a func (123)?

no lo describiría la operator() de std::function como 'generado' (que es un miembro regular), pero por lo demás que es una buena descripción. Las optimizaciones dependen de su compilador, pero tenga en cuenta que para optimizar el direccionamiento indirecto de std::function (que requiere el uso de borrado de tipo) un compilador puede necesitar realizar actos heroicos.

¿Dónde vive el functor que std :: bind genera? ¿En qué alcance? ¿Y cómo std :: bind lo nombra? (Puede haber colisiones de nombres)

La llamada a std::bind devuelve un funtor de tipo no especificado, y una copia de ese funtor se almacena dentro del objeto x. Esta copia durará hasta x. No hay ningún nombre involucrado, así que no estoy seguro de lo que quieres decir con eso.

¿Puede lambdas reemplazar todos los usos de std :: bind?

Nº Considere auto bound = std::bind(functor, _1); donde functor es un tipo con un operator() sobrecargado, digamos que en long y int. Entonces bound(0L) no tiene el mismo efecto que bound(0) y no puede replicar eso con un lambda.

¿Es std :: bind tan óptimo como implementarlo como un lambda?

Depende del compilador. Mídete.

¿Qué sucede con la sintaxis del argumento de la plantilla de std :: function? ¿Cómo se analiza y cómo puedo usar esa sintaxis de argumento de la plantilla en otro lugar?

Es un tipo de función. Quizás ya esté familiarizado con la sintaxis de los punteros/referencias a funciones: void(*)(), int(&)(double). A continuación, simplemente quite el puntero/referencia del tipo, y solo tiene un tipo de función: void(), int(double). Puede utilizar los así:

typedef int* function_type(long); 
function_type* p; // pointer to function 
+2

+1 para la única respuesta correcta a la pregunta # 2: un functor es solo un objeto, no hay una generación de clase mágica involucrada. –

+1

Clavado el polimorfismo estático (bind) vs. prototipos monomórficos (función <>) diferencia la primera vez :) Una diferencia bastante profunda pero que se pasa por alto fácilmente. (Tuviste mi +1 desde el principio) – sehe

+0

+1 para el caso de uso de 'bind' que no se puede replicar con lambda. –

6

1. ¿x(123) realmente llama al operator() generado que funcionó std::function que a su vez llama al operator() del functor que std::bind generó que finalmente llama a func? ¿Esto se optimiza en algo tan óptimo como llamar al func(123)?

Si tiene habilitadas las optimizaciones, el 'material' se inserta y puede contar con que es tan óptimo como llamar al func(123).

2. ¿Dónde se genera el functor que genera std::bind? ¿En qué alcance? ¿Y cómo lo llama std::bind? (Puede haber colisiones de nombres)

precisando: bind genera una 'fugaz', definido por la implementación, se unen a la expresión, que es asignable a function<>. La función es solo una plantilla de clase (Gracias, Luc T.). Y vive en la biblioteca estándar. Sin embargo, las expresiones de enlace están definidas por la implementación.

La biblioteca estándar tiene vienen con rasgos (std::is_bind_expression<>) para permitir la detección MPL de tales expresiones. Una característica decisiva de las expresiones bind sobre std :: function es que son (como yo llamaría) objetos callificables diferidos (es decir, que conservan la semántica completa del sitio de llamadas, incluida la capacidad de seleccionar sobrecargas en el sitio de la aplicación real). std::function<>, por otro lado, se compromete con un único prototipo y almacena internamente el callable object por borrado de tipo (piensa variant o any).

3. ¿Pueden las lambdas reemplazar todos los usos de std :: bind?

4. ¿Es std :: bind tan óptimo como implementarlo como un lambda?

AFAICT lambdas debería compilarse hasta casi lo mismo que las expresiones de vinculación. Una cosa que yo creo lambda no pueden hacer que las expresiones se unen puede es nested bind expressions Editar Mientras que el lenguaje específico de las expresiones unen anidadas no se replicable usando lambdas, lambdas son, por supuesto, capaz de expresar (casi) la misma mucho más natural:

bind(f, bind(g, _1))(x); 
// vs. 
[](int x) { f(g(x)); }; 

 

5. ¿Qué pasa con la sintaxis del argumento de plantilla de std::function? ¿Cómo se analiza y cómo puedo usar esa sintaxis de argumento de la plantilla en otro lugar?

Es sólo una firma de función (la tipo de una función), que se pasa como parámetro de plantilla.

También puede usarlo como un tipo de parámetro de función, que degrada a un puntero de función (similar a cómo los parámetros de valor de matriz se degradan a los indicadores, ¡Gracias David!). En la práctica, la mayoría en cualquier lugar, siempre y cuando usted no tiene una necesidad de nombre de una variable/Tipo:

void receiveFunction(void(int, double)); // spunky 'function<>'-style syntax 

void sample(int, double) { } 

int main() 
{ 
    receiveFunction(sample); 
} 

void receiveFunction(void (*f)(int, double)) // boring 'old' style syntax 
//     void (f)(int, double) // ... also ok 
{ 
    // .. 
} 
+0

Suponiendo que 'f' y' g' no están sobrecargados, la expresión de enlace anidado se puede expresar como un lambda: '[] (T t) {return f (g (t)); } ' –

+0

@LucDanton: encontró la información en su respuesta. +1 por eso – sehe

+1

No estoy de acuerdo con el punto 2: la respuesta correcta es que no hay un functor "generado" por 'bind', solo un objeto temporal devuelto por una función, que no tiene nombre y vivirá durante el tiempo de la expresión aparece en (como todos los temporales). Este temporal se usa para inicializar 'x'. –

0

Pueden lambdas reemplazar todos los usos de std :: unirse?

C++ 14 permitirá a lambdas reemplazar principalmente a bind. Respondiendo en particular a la respuesta de Luc Danton, en C++ 14, puede escribir lambdas con plantillas utilizando auto de manera que bound(0) y bound(0L) se comporten de manera diferente.

Cuestiones relacionadas