¿Cuál es la idea general de un delegado en C ++? ¿Qué son, cómo se usan y para qué se usan?
Primero me gustaría aprender sobre ellos en forma de 'caja negra', pero un poco de información sobre las entrañas de estas cosas también sería genial.
Esto no es C ++ en su forma más pura o más limpia, pero noto que la base de código donde trabajo los tiene en abundancia. Espero entenderlos lo suficiente, para poder usarlos y no tener que profundizar en el horrible horror de la plantilla anidada.
Estos dos artículos de The Code Project explican lo que quiero decir, pero no de manera particularmente sucinta:
c++
delegates
delegation
Sir Yakalot
fuente
fuente
delegate
no es un nombre común en lenguaje c ++. Debe agregar información a la pregunta para incluir el contexto en el que la ha leído. Tenga en cuenta que si bien el patrón puede ser común, las respuestas pueden diferir si habla de delegado en general, o en el contexto de C ++ CLI o cualquier otra biblioteca que tenga una implementación particular de delegado .Respuestas:
Tiene una cantidad increíble de opciones para lograr delegados en C ++. Aquí están los que me vinieron a la mente.
Opción 1: functores:
Se puede crear un objeto de función implementando
operator()
Opción 2: expresiones lambda (solo C ++ 11 )
Opción 3: punteros de función
Opción 4: puntero a funciones miembro (solución más rápida)
Ver Delegado Fast C ++ (en The Code Project ).
Opción 5: std :: function
(o
boost::function
si su biblioteca estándar no lo admite). Es más lento, pero es el más flexible.Opción 6: enlace (usando std :: bind )
Permite establecer algunos parámetros de antemano, conveniente llamar a una función miembro por ejemplo.
Opción 7: plantillas
Acepte cualquier cosa siempre que coincida con la lista de argumentos.
fuente
std::bind
, y ambos realmente hacen lo mismo, excepto que las lambdas no son polimórficas en el sentido de que pueden aceptar diferentes tipos de argumentos.binding
en mi lista). No puede lograr esto con punteros de función.Un delegado es una clase que envuelve un puntero o referencia a una instancia de objeto, un método miembro de la clase de ese objeto que se llamará en esa instancia de objeto, y proporciona un método para activar esa llamada.
Aquí hay un ejemplo:
fuente
Execute()
que activa la llamada de función en el objeto que el delegado envuelve.La necesidad de implementaciones de delegados de C ++ es una vergüenza duradera para la comunidad de C ++. A todos los programadores de C ++ les encantaría tenerlos, por lo que eventualmente los usan a pesar de los hechos que:
std::function()
utiliza operaciones de almacenamiento dinámico (y está fuera del alcance de la programación integrada seria).Todas las demás implementaciones hacen concesiones hacia la portabilidad o la conformidad estándar en mayor o menor grado (verifique inspeccionando las diversas implementaciones de delegados aquí y en el proyecto de código). Todavía tengo que ver una implementación que no use wild reinterpret_casts, "prototipos" de clase anidada que con suerte producen punteros de función del mismo tamaño que el que pasó el usuario, trucos del compilador como primero declarar hacia adelante, luego escribirdef y luego declarar nuevamente, esta vez heredando de otra clase o técnicas de sombra similares. Si bien es un gran logro para los implementadores que lo crearon, sigue siendo un triste testimonio de cómo evoluciona C ++.
Solo en raras ocasiones se señala que ahora, con más de 3 revisiones estándar de C ++, los delegados no fueron abordados adecuadamente. (O la falta de características de lenguaje que permitan implementaciones directas de delegados).
Con la forma en que las funciones lambda de C ++ 11 están definidas por el estándar (cada lambda tiene un tipo anónimo diferente), la situación solo ha mejorado en algunos casos de uso. Pero para el caso de uso de delegados en las API de bibliotecas (DLL), las lambdas por sí solas aún no son utilizables. La técnica común aquí es empaquetar primero el lambda en una función std :: y luego pasarlo a través de la API.
fuente
std::function
no siempre se asigna dinámicamenteMuy simple, un delegado proporciona funcionalidad sobre cómo DEBE funcionar un puntero de función. Hay muchas limitaciones de los punteros de función en C ++. Un delegado usa algo de desagradable plantilla detrás de escena para crear una función de tipo de puntero de función de clase de plantilla que funcione de la manera que desee.
es decir, puede configurarlos para que apunten a una función determinada y puede pasarlos y llamarlos cuando y donde quiera.
Aquí hay algunos muy buenos ejemplos:
fuente
Una opción para delegados en C ++ que no se menciona aquí es hacerlo al estilo C usando una función ptr y un argumento de contexto. Este es probablemente el mismo patrón que muchas personas que hacen esta pregunta intentan evitar. Pero, el patrón es portátil, eficiente y se puede usar en código incrustado y kernel.
fuente
Windows Runtime equivalente de un objeto de función en C ++ estándar. Se puede usar toda la función como parámetro (en realidad, es un puntero de función). Se utiliza principalmente en conjunción con eventos. El delegado representa un contrato que los manejadores de eventos cumplen mucho. Facilita cómo puede funcionar un puntero de función.
fuente