¿Hay algún recurso sobre cómo identificar los problemas que podrían resolverse mejor con plantillas?

8

Decidí mejorar mis conocimientos en metaprogramación de plantillas. Conozco la sintaxis y las reglas, y he estado jugando con innumerables ejemplos de recursos en línea.

Entiendo cuán poderosas pueden ser las plantillas y cuánta optimización del tiempo de compilación pueden proporcionar, pero todavía no puedo "pensar en plantillas", parece que no puedo saber por mí mismo si un cierto problema podría resolverse mejor con plantillas y si puede, cómo adaptar ese problema a las plantillas.

¿Existe algún tipo de recurso o libro en línea que enseñe cómo identificar problemas que podrían resolverse mejor con plantillas y cómo adaptar ese problema?

savia
fuente
55
Si todo lo que tiene es un martillo, todo parece un clavo ;-) No intente demasiado pensar en usar plantillas para todo y, al menos, no si no va a diseñar la próxima versión del estándar C ++ biblioteca.
Doc Brown
tienes razón, no voy a mirar el código de producción e intentar ajustar TMP en todas partes je: p esto es solo para el aprendizaje personal, porque sé cuán poderosos pueden ser y me encanta cómo algunos grandes programadores de C ++ (como STL que trabaja en MS) puede aplicar TMP tan rápido a un problema dado y se ve increíble. STL tiene algunos videos en el canal 9 que realmente me impresionaron acerca de TMP, por eso quiero aprender más.
savia

Respuestas:

8

Libros:

Diseño moderno de C ++

Metaprogramación de plantilla C ++

Estar familiarizado con la recursividad y la programación funcional es una gran ventaja, ya que eso es lo que implica mucha tmp. Se está completando y, por lo tanto, esencialmente todo es posible, aunque generalmente se reduce a aplicar funciones puras a constantes o generar tipos de otros tipos.

Advertencia: tmp es un monstruo feo que convierte un buen código en espagueti. Cuanto más lo use, menos le gustará C ++. Es una cosa malvada.

Pubby
fuente
1
+1 para "tmp es un monstruo feo". C ++ es bueno en algunas cosas, como cualquier lenguaje; pero la metaprogramación no es una de ellas.
Jon Purdy
El "diseño moderno de C ++" es un clásico, pero el IIRC se trata más de implementar cosas utilizando ingeniosos trucos de plantilla que de decidir qué se debe implementar como plantilla. El no. Un principio para eso es probablemente "no": las razones más comunes para necesitar una plantilla ya están cubiertas por la biblioteca estándar (especialmente C ++ 11), Boost y otras bibliotecas ya existentes, por lo que necesita rodar su lo suyo no es realmente algo cotidiano.
Steve314
C ++ Template Metaprogramming es solo el manual de usuario de una parte de boost. No le enseña mucho sobre cómo elegir la aplicación para la que es pertinente ni sobre cómo hacer cosas similares en C ++.
Programador del
6

Aprenda Haskell o algún otro lenguaje funcional puro (Lisp, Scheme, OCaml, por nombrar algunos, puede encontrar más en Wikipedia ).

Teniendo en cuenta Haskell, puede encontrar más información sobre sus instalaciones de metaprogramación aquí .

La programación de plantillas sigue las mismas reglas en realidad.

Macke
fuente
1
Tenga en cuenta que Haskell tiene su propio sistema de plantillas: Template Haskell.
2
@ MattFenwick: Sí. Y sigue siendo Haskell, a diferencia de las plantillas de C ++. :)
Macke
No he trabajado con un lenguaje funcional desde el esquema en la universidad. no es que no me guste, simplemente nunca tuve la oportunidad de trabajar y si tengo que pasar mi tiempo libre codificando o aprendiendo más, simplemente prefiero aprender algo más (¡como TMP!) :)
sap
@sap: Bueno, necesitas entrar en el mismo modo de pensar ...
Macke
@sap: En realidad, Scheme podría ser un gran lenguaje para acostumbrarse a la metaprogramación en tiempo de compilación. Su sistema macro es extremadamente capaz y elegante, al tiempo que logra un efecto similar a las plantillas de C ++ (creo. No he usado demasiado C ++).
Tikhon Jelvis
2

El hecho de que pueda hacer algo con las plantillas no significa que deba hacerlo. En términos prácticos, a menos que cuando esté diseñando piense que este es un trabajo increíble para las plantillas, probablemente sea mejor no usarlas. Si piensas demasiado en las plantillas, solo creas un código increíblemente abstracto que es tan malo como una sola función gigante.

Ryathal
fuente
gracias por la respuesta, sí, entiendo eso, solo quiero aprender :)
sap
Estoy de acuerdo con lo anterior. En los casos en que he usado plantillas, generalmente fue el resultado de refactorizar el código existente. Una vez que esté utilizando su código original de nuevas maneras, la plantilla aparece más claramente como una mejora del original. Es más difícil saber si una plantilla es útil al hacer el diseño antes de tener casos de uso conocidos.
Sam Goldberg
2

Tenga en cuenta que las plantillas son la mejor solución es muy raro. Solo he definido el mío una vez en los últimos 5 años, y mis colegas que revisaron ese código nunca lo habían hecho. Los casos en los que las plantillas tienen mucho sentido ya se han implementado en su mayoría en bibliotecas estándar.

Para la programación genérica, lo que debe tener en cuenta es que está copiando y pegando funciones para realizar solo cambios menores, como en constantes o tipos, y no puede encontrar una forma limpia de usar algo como la herencia o los parámetros de función para evitar repetir tú mismo.

Una forma bastante común de usar plantillas es para la seguridad de tipos, si tiene tipos que se comportan igual, pero por cualquier razón no desea que se mezclen accidentalmente.

Para el cálculo del tiempo de compilación usando plantillas, lo que hay que tener en cuenta son los cálculos intensivos en recursos donde todas sus entradas son conocidas en el momento de la compilación, pero donde se usan diferentes entradas constantes en diferentes lugares a lo largo del código. Sin embargo, tenga en cuenta que esto ralentizará sus compilaciones cada vez, por lo que a menudo es preferible codificar los resultados de forma manual, si no cambian con mucha frecuencia.

Algunos defensores usan plantillas para microoptimizaciones, como evitar búsquedas de tablas virtuales con polimorfismo estático o para desenrollar bucles, pero en mi opinión, la complejidad generalmente supera las ganancias de rendimiento a menos que su código sea muy crítico para el rendimiento.

Karl Bielefeldt
fuente
Muchas gracias por la respuesta, tendré en cuenta esos puntos. Sé que no puedo usarlo para todo (como alguien dijo antes, no puedo comenzar a ver todo como un "clavo") y si entiendo correctamente TMP sobresale en el desarrollo de la biblioteca (todo C ++ lo hace), estoy haciendo esto solo para aprender y NO para aplicarlo en cada código de producción que creo a partir de ahora. y wow solo una vez en 5 años? Supongo que eso muestra lo raro que TMP puede REALMENTE mejorar el código.
savia
2

Básicamente, hay varias buenas razones para usar plantillas:

  1. Tiene una función o una clase que tiene la misma funcionalidad para diferentes tipos. Un buen ejemplo de buen uso de plantillas es la biblioteca boost
  2. desea utilizar el polimorfismo estático y obtener errores de compilación, en lugar de errores de tiempo de ejecución
  3. Desea obtener un comportamiento específico dependiendo de algunos parámetros estáticos. Por ejemplo, boost :: type_traits proporciona muy buenos ejemplos.
BЈовић
fuente
¡Gracias! He usado rasgos tipo antes, ¡cosas realmente geniales! ¿enable_if también es un rasgo de tipo? o simplemente una "condición" de SFINAE? porque lo he usado antes (en la revisión de código) y parecía muy poderoso, pero no lo aplico a diferentes problemas.
savia
@sap Es un rasgo de tipo, que se puede implementar usando SFINAE.
B 29овић
1

¡Definitivamente deberías buscar plantillas en C ++! Esto lo ayudará en gran medida a comprender temas como Patrones de diseño y Programación genérica. Compárelos con lo que otros idiomas le ofrecen. En concreto, debe usar plantillas particularmente en los siguientes escenarios:

  1. Generalización y reutilización de código
  2. Flexibilidad
  3. Restricciones de tiempo y presupuesto
  4. Falta de experiencia para una determinada tarea.

Aquí hay un buen recurso en línea para usted: http://en.wikipedia.org/wiki/Generic_programming#Templates_in_C.2B.2B

Maxood
fuente
Sé para qué se pueden usar, no solo para aplicar ese conocimiento a problemas dados, sino también una buena lectura, gracias :)
sap
1

Un indicador simple de cuándo una plantilla mejoraría su código, es cuando ve que su código con frecuencia requiere que eche un objeto a un tipo diferente. Un ejemplo que encontré en mi propio código Java, que me activó para convertir una firma de método existente en una plantilla:

    public MsgBase getLastSentMessage(Class<? extends MsgBase> msgBaseClass)

Mi código de cliente siempre se veía así:

    OrderResponse response = (OrderResponse) getLastSentMessage(OrderResponse.class);

y cada vez que usaba ese método, tenía que convertir el resultado a la subclase correcta del tipo MsgBase. La firma del método mejorado fue:

    public <T extends MsgBase> T getLastSentMessage(Class<T> clazz)

Ahora el código del cliente era:

     OrderResponse response = getLastSentMessage(OrderResponse.class);

Para resumir, si te encuentras haciendo una gran cantidad de casting que parece innecesario, puedes tener un buen caso en el que una plantilla limpiará tu código.

Actualización: una mejor manera de generalizar la declaración anterior:

Cuando su clase fuente será utilizada por objetos de muchos tipos diferentes, y la clase fuente puede interactuar con esos tipos en un nivel más alto (más abstracto), pero sus clases cliente quieren interactuar con subtipos específicos, ese es un caso para usar plantillas . (Las clases Contenedor / Lista son el ejemplo bien conocido).

Sam Goldberg
fuente
Esto es muy interesante y nunca pensé en aplicar TMP de esa manera, solo demuestra que realmente necesito aprenderlo mejor y practicar más.
savia
Todavía estoy tratando de averiguar los votos negativos aquí. Respondí la pregunta directamente y proporcioné un ejemplo concreto de cuándo surge una plantilla de una refactorización. Entonces, ¿qué estaba mal?
Sam Goldberg
0

Justo hoy, utilicé plantillas para implementar una máquina de estados finitos para obtener algunas entradas. Las plantillas de expresión son herramientas extremadamente poderosas para implementar conceptos de código como ese: se ejecutan como C ++ optimizado a mano y son obscenamente rápidas, pero muy genéricas y muy fáciles de escribir.

En términos generales, las plantillas tienen más sentido al implementar algoritmos genéricos. Si no está implementando un algoritmo genérico, no tienen mucho sentido.

DeadMG
fuente
0

Los usos más comunes de las plantillas son los siguientes:

std::vector<int> vec;
std::map<int, float> mymap;

Entonces el siguiente ejemplo común es:

template<class T>
class MyArray {
public:
   virtual T get(int i) const=0;
};

Junto con este tipo de uso:

class ArrayImpl : public MyArray<float> {
public:
     float get(int i) const { }
};

Ese mostró una parte importante de las plantillas, que es la sustitución de tipos: T se reemplaza por tipo flotante en ambos lugares donde se usa.

tp1
fuente