2010-09-20 18 views
14

¿Existe alguna vez un patrón de dependencias tal que sea imposible mantener todo en archivos de encabezado solamente? ¿Qué pasa si aplicamos una regla de una clase por encabezado solamente?¿Alguna vez es imposible escribir una biblioteca de solo encabezado?

A los efectos de esta pregunta, vamos a ignorar las cosas estáticas :)

+0

¿Qué pasa si la biblioteca A sin encabezado depende de la biblioteca B solo DLL? ¿O eso está descartado por la última oración? Por supuesto, siempre puedes volver a implementarlo como encabezados, por lo que tal vez no sea imposible. – Skurmedel

+0

¿tiene que hablar con otros idiomas? – Anycorn

+0

@Skurmedel: C++ no define ninguna facilidad de tipo DLL, por lo que se especificará la implementación. Sin embargo, dudo que haga la diferencia. –

Respuesta

7

soy consciente de ninguna característica en C++ estándar, a excepción de la estática, que ya hemos mencionado, las cuales requieren una biblioteca para definir una unidad de traducción completa (en lugar de solo encabezados). Sin embargo, no se recomienda hacer eso, porque cuando lo haces, obligas a todos tus clientes a recompilar toda su base de código cada vez que cambia tu biblioteca. Si está utilizando archivos fuente o una biblioteca estática o una forma de biblioteca dinámica de distribución, su biblioteca puede ser modificada/actualizada/modificada sin obligar a todos a recompilar.

+4

"obliga a todos sus clientes a recompilar toda su base de código cada vez que cambia su biblioteca"; lo que es aún peor, en la práctica, los obliga a recompilar su biblioteca cada vez que cambia su código base. –

+4

Aunque hace que la biblioteca sea trivial de usar, y ayuda al compilador cuando optimiza. – GManNickG

+2

@GMan: Depende del compilador. IIRC, tanto GCC como MSVC tienen ahora instalaciones de generación de código de tiempo de enlace para compilaciones de lanzamiento, que eliminan la mayoría (si no todas) las posibles diferencias de rendimiento. –

2

La regla de una clase por encabezado no tiene sentido. Si esto no funciona:

#include <header1> 
#include <header2> 

continuación algunas variaciones de esta voluntad:

#include <header1a> 
#include <header2> 
#include <header1b> 

Esto podría resultar en menos de una clase por cabecera, pero siempre se puede utilizar (void *) y cilindros y funciones en línea (en cuyo caso el 'compilador' probablemente ignorará debidamente 'en línea'). Así que la pregunta, me parece, se puede reducir a:

class A 
{ 
// ... 
void *pimpl; 
} 

¿Es posible que la puesta en práctica privada, pimpl, depende de la declaración de A? Si es así, pimpl.cpp (como encabezado) debe preceder y seguir a A.h. Pero como siempre puede, una vez más, usar (void *) y moldes y funciones en línea en encabezados anteriores, se puede hacer.

Por supuesto, podría estar equivocado. En cualquier caso: Ick.

+2

No veo por qué alguien usaría cualquier tipo de clase de pimpl en una biblioteca solo de encabezado, dado que la idea de si el lenguaje pimpl es dividir las cosas en unidades de traducción separadas ... –

+0

Estoy de acuerdo, no tiene sentido tratar de creando una biblioteca de solo encabezado cuando la implementación es claramente inadecuada para él. Tal vez eso no es lo que querías decir;) Expliqué el pimpl como una herramienta para demostrar que se podía hacer (usando la palabra 'probar' muy libremente). – paul

5

Es posible, diría, en la condición expresa de no utilizar varias funciones de idioma: como notó, algunos usos de la palabra clave static.

Puede requerir varios trucos, pero pueden ser revisados.

  1. Deberá mantener la distinción de encabezado/origen cada vez que necesite romper un ciclo de dependencia, aunque los dos archivos serán archivos de encabezado en la práctica.
  2. Las funciones gratuitas (sin plantilla) deben declararse en línea, el compilador puede no alinearlas, pero si se declaran, no se quejarán de que se hayan redefinido cuando el cliente construye su biblioteca/ejecutable.
  3. Los datos compartidos globalmente (variables globales y atributos estáticos de clase) deben emularse utilizando el atributo estático local en funciones/métodos de clase. En la práctica, importa poco para la persona que llama (solo agrega ()). Tenga en cuenta que en C++ 0x esto se convierte en la manera preferida porque se garantiza que sea seguro para subprocesos al tiempo que protege del fiasco orden de inicialización, hasta entonces ... no es seguro para subprocesos;)

El respeto de los 3 puntos, creo que sería capaz de escribir una biblioteca exclusiva de solo encabezado (¿alguien ve algo más que me perdí?)

Varias bibliotecas Boost han usado trucos similares para ser solo de encabezado aunque su código era no completamente plantilla.Por ejemplo Asio hace muy consciente y propone la alternativa usando banderas (ver release notes for Asio 1.4.6):

  • clientes que sólo necesitan un par de características que no necesita preocuparse acerca de la construcción/vinculación, que acaba de agarrar lo que necesitan
  • clientes que confían en él un poco más o que desee reducir el tiempo de compilación se les ofrece la posibilidad de construir su propia biblioteca Asio (con su propio conjunto de banderas) y luego incluir encabezados "ligeros"

esta manera (en el precio de un poco más de esfuerzo por parte de los desarrolladores de la biblioteca) los clientes obtienen su pastel y cómelo también Es una solución bastante agradable, creo.

Nota: me pregunto si static funciones podrían ser inline, yo prefiero usar espacios de nombres anónimos a mí mismo por lo que nunca realmente se veía en él ...

+0

re # 1: ¿Se puede esbozar un escenario donde sería necesario? Traté de imaginar uno, pero no pude encontrar nada que no se pueda resolver moviendo las definiciones de funciones en línea detrás de todas las definiciones necesarias. – sbi

1

En mi larga carrera, no he llegado a través de la dependencia patrón que no permitiría la implementación de solo encabezado. Tenga en cuenta que si tiene dependencias circulares entre clases, puede necesitar recurrir a la interfaz abstracta - paradigma de implementación concreta, o usar plantillas (usar plantillas le permite reenviar las propiedades/métodos de parámetros de la plantilla, que son resuelto más tarde durante la instanciación).

Esto no significa que siempre DEBE apuntar a bibliotecas con encabezado único. Bueno como son, deberían reservarse para la plantilla y el código en línea. NO DEBEN incluir cálculos complejos sustanciales.

Cuestiones relacionadas