Решено: Шаблонные классы и многофайловые исходники (Линкер офигел)

Модератор: Модераторы разделов

Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Решено: Шаблонные классы и многофайловые исходники

Сообщение VoidExp »

Привет всем! Очередная трудность появилась на пути изучения C++. В общем, как обычно, привожу ситуацию:

Имеются два файла, header.h & source.cc

header.h

Код: Выделить всё

template <class Type>
class Dummy
{
    public:
        Dummy() {};
       ~Dummy() {};
        void PrintSomeValue(Type value);
};


source.cc

Код: Выделить всё

#include "header.h"
template <class Type>
void Dummy<Type>::PrintSomeValue(Type value)
{
    cout << value << endl;
}


Если допустим метод объекта класса Dummy PrintSomeValue() вызывается с аргументом типа int или любого другого основного типа, линкер выдает ошибку типа

Код: Выделить всё

undefined reference to "void Dummy<int>::PrintSomeValue(int)

Все работает хорошо если и интерфейс класса и его реализация написаны в одном файле. Собираю таким образом:

Код: Выделить всё

g++ source.cc -c -o build/source.o $(CFLAGS)
g++ main.cc -c -o build/main.o $(CFLAGS)
g++ build/source.o build/main.o $(LIBS)


Содержимое main.cc довольно таки банальное, так что не стану приводить. Там просто создается объект Dummy<int> и вызывается функция PrintSomeValue(int).
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение sergio »

VoidExp писал(а):
01.11.2007 12:51
Имеются два файла, header.h & source.cc
header.h
source.cc

Код: Выделить всё

#include "header.h"
template <class Type>
void Dummy<Type>::PrintSomeValue(Type value)
линкер выдает ошибку типа
[code]undefined reference to "void Dummy<int>::PrintSomeValue(int)

Все работает хорошо если и интерфейс класса и его реализация написаны в одном файле. Собираю таким образом:

Недавно обсуждалось. В срр файл выносятся только полные специализации методов. Шаблонные определения методов должны быть видны компилятору-линковщику, поскольку метод<тип> генерируется в тот момент, когда он в коде используется. Если вы их воносите в срр файл и пытаетесь его скомпилировать - он пустой, из шаблона ничего не генерируется.
Т.е. шаблонные определения, также как определения inline-функций, должны быть видны.
Чтобы не забивать ими заголовочный файл, их иногда выносят в отдельный файл, который инклудится в конец заголовка.
Также как с инлайн функциями, многожественные включения определений шаблонных методов компилятор-ликовщик принимает и сам с ними разбирается.
(Отсюда одно из следствий увлечения шаблонами - потеря раздельной компиляции и заметный рост времени компиляции...)
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение serzh-z »

Странный подход к использованию шаблонов...

Специализация шаблона происходит в main.cc - на этапе компиляции же source.cc информация о спецификаторе недоступна, потому и не существует функции "void Dummy<int>::PrintSomeValue(int)".
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение VoidExp »

а чего тут странного? наверное моя цель непонятна... я хочу сделать заголовочный файл, в котором находится интерфейс класса. его-же имплементация находится в другом файле, чтобы поддерживать чистоту. а в main включается заголовочный файл чтобы использовать шаблон. но все-таки я не понял как решить проблему
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение serzh-z »

VoidExp писал(а):
01.11.2007 14:35
а в main включается заголовочный файл чтобы использовать шаблон.
Шаблоны призваны решать другую цель. Насколько я знаю, из современных компиляторов экспорт шаблонов поддерживает лишь один-два. А код выше похож на именно попытку экспорта шаблона.

Если уж так хочется, не смотря ни на что, собрать программу выше, то добавление в source.cc:
void Dummy<int>::PrintSomeValue(int value)
{
std::cout << value << std::endl;
}
решит проблему... Но в этом случае я не вижу смысла в использовании шаблонов.

Либо можно сделать как указал sergio:
sergio писал(а):
01.11.2007 13:27
Чтобы не забивать ими заголовочный файл, их иногда выносят в отдельный файл, который инклудится в конец заголовка.
но, имхо, это некрасиво.
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение VoidExp »

Значит для использования шаблона надо написать его интерфейс и реализацию в одном и том-же файле?
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение serzh-z »

VoidExp писал(а):
01.11.2007 15:01
интерфейс и реализацию в одном и том-же файле?
Примерно так.
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение VoidExp »

По моему это несколько нарушает принцип инкапсуляции... Других выходов нету? А то при массивном использовании шаблонов, читабельность кода будет под вопросом.
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение sergio »

VoidExp писал(а):
01.11.2007 16:16
По моему это несколько нарушает принцип инкапсуляции... Других выходов нету? А то при массивном использовании шаблонов, читабельность кода будет под вопросом.

Это нарушает принцип раздельной компиляции - если вы определяете шаблонные методы в заголовочных файлах.Так же, как и инлайн функции. Обойти это нельзя. Как сказал serzh-z, экспорт шаблонов почти нигде не поддерживается, и смысла в нем не так много.
Если вы их определения дублируете по всем файлам, где используете - тогда получаете просто кашу. ))
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение serzh-z »

VoidExp писал(а):
01.11.2007 16:16
По моему это несколько нарушает принцип инкапсуляции...
Это ничуть не нарушает принцип инкапсуляции... Инкапсуляция - это не физическое сокрытие исходного кода от программиста, это всего лишь условное скрытие деталей реализации от пользователя класса средствами компилятора.
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение VoidExp »

Вот именно. Гораздо приятнее иметь дело с интерфейсом чем с его реализацией тоже. Еще вопрос, как использовать шаблоны как параметры шаблонов? Например, возможно-ли такое:

Вектор<Список<целые>>
Спасибо сказали:
sergio
Сообщения: 436
Статус: Интересующийся новичок
ОС: Debian GNU/Linux 4 & 5

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение sergio »

VoidExp писал(а):
01.11.2007 17:10
Вот именно. Гораздо приятнее иметь дело с интерфейсом чем с его реализацией тоже. Еще вопрос, как использовать шаблоны как параметры шаблонов? Например, возможно-ли такое:

Вектор<Список<целые>>


std::vector<std::list<std::string> > причем list<string> на самом деле
std::list<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > :)
Debian GNU/Linux 4 -- AMD Athlon64 3000+ / Asus 7600GS -- Gnome
Debian GNU/Linux 5 -- Dell (Vostro) 500 (Celeron M560 / iGM965) -- Gnome
Спасибо сказали:
Аватара пользователя
VoidExp
Сообщения: 208
Статус: Lead guitar adept
ОС: Ubuntu

Re: Решено: Шаблонные классы и многофайловые исходники

Сообщение VoidExp »

понятно, спасибо за информацию!
Спасибо сказали: