2009-03-17 5 views
3

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

// 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 в конце.

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

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

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

EDIT:

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

ответ

4

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

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

// 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». Размещать любую #include директивы в отдельный $ ДРЧ и $ в исходные тексты блоков по мере необходимости:

// 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-помощника.

+0

Кажется, это то, что я искал. Хотя, я немного устал, чтобы на самом деле использовать его ... – Frank

-1

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

+0

Как это работает? Мне все равно придется отделять декларации от определений, нет? – Frank

+0

«extern» не поможет во время компиляции, он просто ограничивает то, что создается, когда возникает неявное создание экземпляра. –

1

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

1

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

То, что я придумал, - это рассмотреть проблему наоборот. Пока вы не специализируетесь на своей реализации, он работает грациозно.

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

// 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 */ } 

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

EDIT: о экстерном ключевое слово в C++ 0x

Я считаю, что Экстерн ключевое слово в C++ 0x поможет, но это не решит все волшебно!

this article С,

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

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

extern template class std::vector; 

 Смежные вопросы

  • Нет связанных вопросов^_^