ejemplos - c++ pdf
¿Hay compiladores de c++ optimizados para el uso de plantillas? (8)
Las plantillas de C ++ han sido una bendición en mi trabajo diario debido a su poder. Pero no se puede ignorar el tiempo de compilación (muy, muy, muy largo) que resulta del uso intensivo de plantillas (hola meta-programación y bibliotecas Boost). He leído y probado muchas posibilidades para reorganizar y modificar manualmente el código de la plantilla para que se compile lo más rápido posible.
Ahora me pregunto si hay compiladores de c ++ que intenten minimizar el tiempo necesario para interpretar las clases de plantilla. Puede que esté equivocado, pero creo que los compiladores que conozco solo han agregado la interpretación de la plantilla a sus versiones anteriores.
Mis preguntas son:
- ¿Es el código de plantilla de C ++ tan difícil de interpretar que no hay mucho que optimizar? (lo dudo mucho)
- ¿Hay compiladores de c ++ que realmente optimicen la interpretación de "plantillas de c ++"?
- ¿Hay proyectos para desarrollar una nueva generación de compiladores de c ++ que puedan optimizar esto?
- Si fuera a participar en un proyecto de este tipo, ¿cuáles serían sus directrices?
Creo que las plantillas en sí mismas no son tan complejas en sí mismas. Veremos cuándo se introducen los conceptos en c ++ 0x, etc., pero en este momento, las plantillas son solo (casi) como macros, por lo que el problema real no es si ha optimizado los compiladores de c ++ para las plantillas. El problema es que las plantillas generan una gran cantidad de código al compilar, lo que hace que la compilación sea más lenta.
El enlazador dorado puede ayudar a reducir el tiempo de enlace aproximadamente 5 veces, lo que puede reducir el tiempo de compilación general. Es particularmente útil ya que la vinculación no puede ser paralela de la misma manera que la compilación.
(No es una respuesta directa, pero espero que esto sea útil).
El principal problema con las plantillas es el siguiente:
No puede (normalmente) separar la definición de su clase de plantillas de su declaración y colocarla dentro de un archivo .cpp.
La consecuencia: todo está en archivos de cabecera. Cada vez que incluye un encabezado, incluye una gran cantidad de código que, en circunstancias normales, estaría bien separado en archivos .cpp y compilado por separado. Cada unidad de compilación incluye algunos encabezados, y así, con las plantillas, cada unidad de compilación contiene una gran cantidad de código, o casi todo su proyecto, a través de los encabezados incluidos.
Si ese es tu problema, mira aquí, en una pregunta relacionada:
Obtuvo una muy buena respuesta , que resuelve ese problema .
Básicamente, implica crear una instancia de las plantillas que necesita una vez y compilarlas en un archivo de objeto. Más adelante, puede vincularse con él y no tiene que incluir ese código en todas partes. Se separa en un archivo de objeto compilado. Nota: Eso tiene sentido solo si usa solo unos pocos tipos de plantillas de instancias (por ejemplo, solo necesita MyType<int>
y MyType<double>
en su programa).
Utiliza la bandera g++
-fno-implicit-templates
.
Esa técnica es tan útil que creo que debería incorporarse en las preguntas frecuentes de C ++: [35.12] ¿Por qué no puedo separar la definición de mi clase de plantillas de su declaración y colocarla dentro de un archivo .cpp?
Espero que la compilación de código de plantilla se acelere con tener varias plantillas / referencias de valor. Hoy, si queremos escribir un código de plantilla que haga algo en tiempo de compilación, abusamos de las reglas del lenguaje. Creamos docenas de sobrecargas y especializaciones de plantillas que resultan en lo que queremos, pero no de una manera que le diga al compilador nuestra intención. Así que hay poco acceso directo para el compilador en el momento de la compilación. Ver Motivación para plantillas variad.
¿Hay proyectos para desarrollar una nueva generación de compiladores de c ++ que puedan optimizar esto?
Sí, hay CLang que es una interfaz de lenguaje C para la infraestructura del compilador LLVM. Tanto CLang como LLVM se codifican utilizando C ++. Entre los desarrolladores de CLang se encuentra Douglas Gregor, autor de varias propuestas de lenguaje en C ++ 1x como plantillas variadas y conceptos. Para referencia, vea esta prueba por Douglas Gregor de clang contra GCC
http://www.freeimagehosting.net/uploads/a2e6f1dc27.png
Aquí hay algunos resultados de rendimiento rápido y sucio para la creación de instancias de plantillas en Clang y GCC 4.2. La prueba es muy simple: mida el tiempo de compilación (-fsyntax-only) para una unidad de traducción que calcula el número de Fibthacci N. a través de un metaprograma de plantilla. Clang parece estar escalando linealmente (o cerca de él) con el número de instancias. Y, aunque no puedes verlo en la tabla, Clang es un poco más de 2 veces más rápido que GCC al principio (
Fibonacci<100>
).
CLang aún está en sus inicios, pero creo que tiene buenas posibilidades de convertirse en un gran compilador de C ++.
Esto realmente no es una respuesta a tu pregunta. Es más una observación lateral.
Tampoco soy un abogado de lenguaje C ++, por lo que podría estar fuera de la base con algunos de los detalles.
Pero, la idea aproximada debe ser correcta.
La razón principal por la que los compiladores de C ++ tardan tanto tiempo en compilar los metaprogramas de plantilla se debe a la forma en que se especifican los metaprogramas de plantillas.
No se especifican directamente como el código que desea que ejecute el compilador en el momento de la compilación. Tomemos el ejemplo de calcular la longitud de una lista de tipos.
Si pudieras escribir código como este:
compile_time size_t GetLength(TypeList * pTypeList)
{
return DoGetLength(pTypeList, 0);
}
compile_time size_t DoGetLength(TypeList * pTypeList, size_t currentLength)
{
if (pTypeList)
{
return DoGetLength(pTypeList->Next, ++currentLength);
}
else
{
return currentLength;
}
}
Así fue como se compiló por separado del código donde se usó, y se expuso al lenguaje a través de alguna sintaxis, luego el compilador podría ejecutarlo muy rápidamente.
Simplemente sería una simple función recursiva llamada.
Es posible diseñar un lenguaje que permita ese tipo de cosas. La mayoría de los que hacen esto (como lisp) están tipificados dinámicamente, pero es posible hacerlo con la escritura estática. Sin embargo, no es probable que alguna vez se vea implementado en C ++.
El problema en C ++, sin embargo, es que el código está escrito como:
template <typename First, typename Second>
struct TypeList
{
typedef First Head;
typedef Second Tail;
};
template <>
struct ListSize<NullType>
{
enum { size = 0 };
};
template <typename Head, typename Tail>
struct ListSize<TypeList<Head, Tail> >
{
enum { size = 1 + ListSize<Tail>::size };
};
Para que el compilador "ejecute" el meta-programa tiene que:
- Construya un gráfico de dependencia para los valores iniciales del valor de enumeración de "tamaño"
- Construye un tipo de plantilla para cada borde en el gráfico
- Enlazar todos los símbolos referenciados por cada tipo de plantilla construida
- Ordenar topológicamente el gráfico de dependencia.
- Recorre la gráfica y evalúa las constantes.
Esto es mucho más costoso que simplemente ejecutar un algoritmo recursivo O (N).
El peor de los casos sería algo como O (N * M * L), con N igual a la longitud de la lista, siendo M el nivel de anidamiento del alcance y L el número de símbolos en cada alcance.
Mi consejo sería minimizar la cantidad de meta-programación de plantillas de C ++ que usas.
No va a ser la respuesta que desea, pero Walter Bright fue el principal desarrollador del primer compilador nativo de C ++ y un compilador optimizado para c ++. Después de todo eso, escribió su propio lenguaje de programación llamado D. Es básicamente una mejora en C ++ y se adapta mejor a las plantillas.
No conozco ningún compilador de c ++ que haya optimizado para el uso de plantillas.
Parece que g ++ 4.5 ha hecho un tremendo progreso al tratar con las plantillas. Aquí están los dos cambios inevitables.
"Al imprimir el nombre de una especialización de plantilla de clase, G ++ ahora omitirá cualquier argumento de plantilla que provenga de los argumentos de plantilla predeterminados". Eso podría considerarse una modificación sutil, pero tendrá un impacto enorme en el desarrollo con plantillas c ++ (¿alguna vez escuchó sobre mensajes de error ilegibles ...? ¡No más!)
"El tiempo de compilación para el código que usa plantillas ahora debe escalar linealmente con el número de instancias en lugar de hacerlo de forma cuadrática". Esto va a minar gravemente los argumentos de compilación en contra del uso de plantillas de C ++.
Ver en el sitio de GNU para obtener información completa
En realidad, ¡ya me estoy preguntando si todavía hay problemas con las plantillas de c ++! Mmm, sí, las hay, ¡pero concentrémonos en el lado brillante por ahora!
Prueba Incredibuild . Reduce drásticamente el tiempo de compilación / construcción.
Básicamente, este producto permite a Visual C ++ construir en múltiples máquinas en su organización aprovechando los ciclos de inactividad. He usado Incredibuild en grandes proyectos (500 kloc) con un montón de código de plantilla y obtuve una buena aceleración en los tiempos de compilación.