Автоматически отделять определения классов от объявлений?

StackOverflow https://stackoverflow.com/questions/652779

Вопрос

Я использую библиотеку, которая почти полностью состоит из шаблонные классы и функции в файлах заголовков, так:

// foo.h
template<class T>
class Foo {
  Foo(){}
  void computeXYZ() { /* heavy code */ }
};
template<class T>
void processFoo(const Foo<T>& foo) { /* more heavy code */ }

Это плохо, потому что время компиляции невыносимо всякий раз, когда я включаю один из этих заголовочных файлов (а на самом деле я включаю многие из них в каждый из моих модулей компиляции).

Поскольку в качестве параметра шаблона я все равно использую только один или два типа, которые планирую создать для каждого заголовочного файла библиотеки, файл, содержащий только объявления, без тяжелого кода, вот так:

// NEW: fwd-foo.h
template<class T>
class Foo {
  Foo();
  void computeXYZ();
};
template<class T>
void processFoo(const Foo<T>& foo);

И затем один файл, который создает все экземпляры, которые мне понадобятся.Этот файл может быть составляется отдельно раз и навсегда:

// NEW: foo.cpp
#include "foo.h"
template class Foo<int>;
template class Foo<double>;
template void processFoo(const Foo<int>& foo);
template void processFoo(const Foo<double>& foo);

Теперь я могу просто включить fwd-foo.h в моем коде и имеют короткое время компиляции.Я дам ссылку против foo.o в конце.

Обратной стороной, конечно, является то, что мне приходится создавать эти новые fwd-foo.h и foo.cpp файлы сам.И, конечно же, это проблема обслуживания:Когда выпускается новая версия библиотеки, мне приходится адаптировать их к этой новой версии.Есть ли другие недостатки?

И мой главный вопрос:

Есть ли шанс, что я смогу создать эти новые файлы, особенно fwd-foo.h, автоматически из оригинала foo.h?Мне приходится делать это для многих заголовочных файлов библиотеки (около 20), и лучше всего использовать автоматическое решение, особенно в случае, если выпускается новая версия библиотеки, и мне придется делать это снова с новой версией.Доступны ли какие-либо инструменты для этой задачи?

РЕДАКТИРОВАТЬ:

Дополнительный вопрос:Как новая поддержка extern ключевое слово поможет мне в этом случае?

Это было полезно?

Решение

Мы используем лзз который разбивает один файл на отдельный заголовок и единицу перевода.По умолчанию определения шаблонов обычно также помещаются в заголовок, однако вы можете указать, что вы не хотите, чтобы это происходило.

Чтобы показать вам, как вы можете его использовать, рассмотрим следующее:

// t.cc
#include "b.h"
#include "c.h"

template <typename T> 
class A {
  void foo () {
    C c;
    c.foo ();
    b.foo ();
  }
  B b;
}

Возьмите вышеуказанный файл и скопируйте его в файл «t.lzz».Разместите любой #включать директивы в отдельные блоки $hdr и $src по мере необходимости:

// t.lzz
$hdr
#include "b.h"
$end

$src
#include "c.h"
$end

template <typename T> 
class A {
  void foo () {
    C c;
    c.foo ();
    b.foo ();
  }
  B b;
}

Теперь, наконец, запустите lzz для файла, указав, что он помещает определения шаблонов в исходный файл.Вы можете сделать это с помощью $прагма в исходном файле или вы можете использовать параметр командной строки «-ts»:

В результате будут созданы следующие файлы:

// t.h
//

#ifndef LZZ_t_h
#define LZZ_t_h
#include "b.h"
#undef LZZ_INLINE
#ifdef LZZ_ENABLE_INLINE
#define LZZ_INLINE inline
#else
#define LZZ_INLINE       
#endif
template <typename T>
class A
{
  void foo ();
  B b;
};
#undef LZZ_INLINE
#endif

И:

// t.cpp
//

#include "t.h"
#include "c.h"
#define LZZ_INLINE inline
template <typename T>
void A <T>::foo ()
          {
    C c;
    c.foo ();
    b.foo ();
  }
#undef LZZ_INLINE

Затем вы можете запустить их с помощью некоторых команд grep/sed, чтобы удалить вспомогательные макросы LZZ.

Другие советы

Попробуйте использовать предварительно скомпилированные заголовки. Я знаю, что GCC и MSVC поддерживают эту функцию. Однако использование зависит от продавца.

Я уже давно работаю над той же самой проблемой. В предлагаемом решении вы определяете классы шаблонов дважды. Будет нормально, если он определит те же вещи (в том же порядке), но рано или поздно у вас обязательно возникнут проблемы.

Я пришел к тому, чтобы рассмотреть проблему с другой стороны. Пока вы не специализируете свою реализацию, она работает изящно.

В нем используются два макроса, которые позволяют не обновлять аргументы шаблона в файле реализации (однако, будьте осторожны, если вы хотите добавить аргументы шаблона по умолчанию в класс).

// foo.h
#define FOO_TEMPLATE template<typename T>
#define FOO_CLASS Foo<T>

FOO_TEMPLATE
class Foo {
  Foo();
  void computeXYZ();
};

// foo_impl.h
#include "foo.h"
FOO_TEMPLATE
FOO_CLASS::Foo(){}

FOO_TEMPLATE
void FOO_CLASS::computeXYZ() { /* heavy code */ }

Делая это, вы, по сути, работаете так же, как и с не шаблонными классами (вы можете делать то же самое с шаблонными функциями, конечно).

РЕДАКТИРОВАТЬ: о ключевом слове extern в c ++ 0x

Я верю, что ключевое слово extern в c ++ 0x поможет, но оно не решит все волшебным образом!

Из этой статьи ,

  

Внешние шаблоны

     

Каждый модуль, который создает экземпляр   шаблон по сути создает копию   это в объектном коде. Тогда это   компоновщику распоряжаться всеми   избыточный объектный код в самый последний   этап, тем самым замедляя критическое   цикл редактирования-компиляции-ссылки, составляющий   день программиста (или иногда   грезы). Чтобы замкнуть это   сборка мусора объектного кода,   количество поставщиков компиляторов   уже реализовано ключевое слово extern   это может идти перед шаблонами.   Это случай стандартизации   кодификация существующей отраслевой практики   (каламбур предназначен). На практике это   осуществляется путем отправки уведомления   компилятор в основном для "!"   вот это "

extern template class std::vector;

C ++ 0x исправит проблемы времени компиляции с внешними шаблонами. Хотя я не знаю автоматического способа сделать то, что вы просите.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top