es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Si he separado una plantilla en un encabezado y en una fuente, ¿existe alguna manera de compilarla en su propio archivo de objeto?

Me gusta que los archivos de encabezado existan como referencias autodocumentadas. Trato de mantenerlos como declaraciones con comentarios de documentación, y luego programo toda la implementación en mis archivos fuente. Básicamente, una interfaz documentada.

Estoy trabajando en un proyecto que hace un uso intensivo de plantillas y, en lugar de llenar el encabezado con detalles de implementación (sé que aún puedo declarar las plantillas y definirlas más adelante en el encabezado, pero esto no resuelve esta pregunta), he optado por hacer algo como esto.

// foo.h
template<typename t="">
class Foo {
public:
  Foo();
  T get_foo();
private:
  T foo;
}

#include "foo.tpp"
// foo.tpp
template<typename t="">
Foo<t>::Foo(T f) : foo(f) {};

template<typename t="">
T Foo<t>::get_foo() { return foo; }

Esto tiene una desventaja moderada. Cualquier fuente que use #include "foo.h" debe compilarse completamente cada vez que se modifica foo. Básicamente, esto me ha llevado a tener que recompilar la mayoría o todo el proyecto cada vez que hago un cambio en lo que es (conceptualmente pero no prácticamente) un código independiente.

Entiendo que debido a la forma en que los compiladores de C++ manejan las plantillas, o al estándar del lenguaje, o a alguna combinación de ambos, cuando el compilador encuentra una situación en la que se necesita una sustitución como auto f = Foo<int>();, necesita tener disponible la definición completa de Foo<int> para realizar correctamente la sustitución.

¿No hay forma alguna de evitar esto? En esta situación, al menos me parece que dado foo.tpp como un archivo fuente, el compilador podría expandir fácilmente los argumentos de plantilla para ambos y compilarlos como si fueran un archivo de encabezado/fuente normal como una TU independiente. Luego, el enlazador solo necesita encontrarlos más adelante para resolver la definición de Foo<int> en la etapa final de enlace.

Supuestamente, este ejemplo está simplificado y hay casos más complicados y advertencias que he pasado por alto. Me pregunto si hay alguna forma práctica de evitar esto. Estoy considerando escribir un script para realizar la sustitución por mí y luego compilar esos archivos, pero esperaba que hubiera un método conocido y más generalizado.

Tags:  ,

Answer

  1. Avatar for davy.ai

    El autor del código se enfrenta a un dilema con respecto a las plantillas y encabezados autoexplicativos. Han decidido implementar las plantillas en un archivo separado (foo.tpp) para evitar saturar el archivo de encabezado (foo.h) con detalles de implementación. Sin embargo, esto ha llevado al problema de que cualquier código fuente que incluya foo.h debe ser completamente recompilado cada vez que se cambie foo.tpp, lo cual puede ser demasiado tiempo consumidor e impráctico en proyectos grandes.

    El autor reconoce que esto se debe a la forma en que los compiladores de C++ manejan las plantillas, que requieren que la definición completa de una plantilla esté disponible para realizar la sustitución. Se preguntan si hay una forma de evitar este problema, como compilar foo.tpp como una Unidad de Traducción (TU) independiente y luego enlazarla. Aunque esto parece ser una solución viable, el autor reconoce que puede haber casos más complicados y advertencias que no han considerado.

    En general, el autor busca una solución práctica al problema de implementar plantillas de una manera que permita encabezados autoexplicativos sin requerir una recompilación completa de todos los archivos fuente que incluyan el encabezado cuando se cambie la plantilla. Puede considerar escribir un script para realizar la sustitución de plantillas o explorar otros métodos para evitar este problema.

Comments are closed.