Шаблоны. Разделение объявления и определения.
От: Dihotom  
Дата: 22.03.10 14:41
Оценка:
Для наглядности буду в вопросах использовать следующий класс my_type_1 с конкретизацией его только int'ом. Предполагаем, что small_func маленькая и мы её хотим сделать подставляемой, а big_func большая сложная функция и хотелось бы её реализацию "спрятать".
// my_type_1.h
template<class T>
class my_type_1
{
public:
    void small_func() { /*...*/ }

    void big_func() { /*...*/ }
};


1. Правильно ли я понимаю, что при использовании шаблонов, совмещающих объявление и определение (как в примере выше), в результирующем исполняемом файле мы получаем столько экземпляров функций my_type_1<int>::big_func, в скольких cpp-файлах она используется (т.е. по одному экземпляру на каждую единицу трансляции)? Зависит ли ответ от компилятора?

2. Правильно ли я понимаю, что если мы сделаем так (см. ниже), то в результирующем исполняемом файле гарантированно всегда будет только один экземпляр my_type_2<int>::big_func, в случае поддержки extern template компилятором? Уменьшится ли время компиляции по сравнению с первым вариантом (с учетом того, что функций типа big_func может быть довольно много)?
// my_type_2.h
template<class T>
class my_type_2
{
public:
    void small_func() { /*...*/ }

    void big_func() { /*...*/ }
};

// my_type_2_int.h
// Подключается для использования my_type_2<int>
#include "my_type_2.h"

extern template void my_type_2<int>::big_func();

// my_type_2_int.cpp
#include "my_type_2.h"

template void my_type_2<int>::big_func();


3. Уменьшится ли время компиляции второго варианта, если мы его модифицируем так:
// my_type_3.h
template<class T>
class my_type_3
{
public:
    void small_func() { /*..*/ }

    void big_func();
};

// my_type_3_impl.h
#include "my_type_3.h"

template<class T>
void my_type_3<T>::big_func() { /*..*/ }

// my_type_3_int.h
// Подключается для использования my_type_3<int>
// Компилятор не видит жирное тело big_func в "клиентских" единицах трансляции. 
#include "my_type_3.h"

extern template void my_type_2<int>::big_func();

// my_type_3_int.cpp
#include "my_type_3.h"
#include "my_type_3_impl.h" // Определение жирных функций

template void my_type_3<int>::big_func(); // Реализация жирных функций
Re: Шаблоны. Разделение объявления и определения.
От: Dihotom  
Дата: 22.03.10 14:52
Оценка:
Еще дополнение...
Для 1. Если ответ на первый вопрос "нет", то о каком разбухании кода говорится при применении шаблонов?
Для 3. В принципе, тут большой плюс получается в том, что мы избавляемся от необходимости перекомпилировать все исходники, использующие my_type_3 при изменении big_func — достаточно пересобрать только все my_type_3_XXX.cpp.
Re[2]: Шаблоны. Разделение объявления и определения.
От: dilmah США  
Дата: 22.03.10 15:02
Оценка:
> 1. Правильно ли я понимаю, что при использовании шаблонов, совмещающих объявление и определение (как в примере выше),
> в результирующем исполняемом файле мы получаем столько экземпляров функций my_type_1<int>::big_func, в скольких cpp-файлах
> она используется (т.е. по одному экземпляру на каждую единицу трансляции)? Зависит ли ответ от компилятора?

компилятор должен метить их особым образом, а линкер убирать дубликаты

D>Для 1. Если ответ на первый вопрос "нет", то о каком разбухании кода говорится при применении шаблонов?


хрестоматийный пример std::sort vs. qsort: у qsort будет один код для всех типов, у std::sort будет по инстанциации для каждого типа с которым ты его используешь.
Re[2]: Шаблоны. Разделение объявления и определения.
От: saf_e  
Дата: 22.03.10 15:59
Оценка:
Здравствуйте, Dihotom, Вы писали:

D>Еще дополнение...

D>Для 1. Если ответ на первый вопрос "нет", то о каком разбухании кода говорится при применении шаблонов?
D>Для 3. В принципе, тут большой плюс получается в том, что мы избавляемся от необходимости перекомпилировать все исходники, использующие my_type_3 при изменении big_func — достаточно пересобрать только все my_type_3_XXX.cpp.

1. Ответ "да". Но линкер выкинет все дубликаты (кстати, на этом, при сборке нескольких либ использующих одинаковые шаблонные классы (типа std::vector) можно получить феерические баги линковки), способ отбрасывания -- не определен.
Распухание -- за счет копии кода для каждого типа.

3. Да, если ситуация позволяет, то лучше прятать реализацию -- значительно ускоряет сборку. Есть и ньюансы. Например, при открытой реализации -- не потребует экспорта из Dll (если это имеет смысл).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.