Шаблоны C++, неопределенная ссылка

У меня есть функция, объявленная так:

template <typename T> 
T read();

и определяется так:

template <typename T>
T packetreader::read() {
    offset += sizeof(T);
    return *(T*)(buf+offset-sizeof(T)); 
}

Однако, когда я пытаюсь использовать его в своей функции main():

packetreader reader;
reader.read<int>();

Я получаю следующую ошибку от g++:

g++ -o main main.o packet.o
main.o: In function `main':
main.cpp:(.text+0xcc): undefined reference to `int packetreader::read<int>()'
collect2: ld returned 1 exit status
make: *** [main] Error 1

Может ли кто-нибудь указать мне правильное направление?


person Daniel Sloof    schedule 16.03.2009    source источник
comment


Ответы (4)


Вам нужно использовать ключевое слово export. Однако я не думаю, что G++ имеет надлежащую поддержку, поэтому вам нужно включить определение функции шаблона в заголовок, чтобы единица перевода могла ее использовать. Это связано с тем, что <int> "версия" шаблона не была создана, а была создана только <typename T> "версия".

Самый простой способ — #include файл .cpp. Однако это может вызвать проблемы, например. когда другие функции находятся в файле .cpp. Это также, вероятно, увеличит время компиляции.

Чистый способ — переместить функции шаблона в отдельный файл .cpp и включить его в заголовок или использовать ключевое слово export и скомпилировать его отдельно.

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

person strager    schedule 16.03.2009
comment
Было бы неплохо, если бы я переместил свой код package.cpp в package.h и переименовал его во что-то вроде package.hpp, как я часто видел, используется в boost? - person Daniel Sloof; 16.03.2009
comment
@Daniel, только если все ваши функции являются функциями шаблона. В противном случае вам может сойти с рук перемещение некоторых ваших функций и сохранение файла .cpp. - person strager; 16.03.2009

Проблема в том, что шаблон функции не является функцией. Это шаблон для создания функций по мере необходимости.

Таким образом, для работы шаблона компилятору интуитивно нужны две части информации: сам шаблон и тип, который следует в него подставить. Это отличается от вызова функции, который компилятор может сгенерировать, как только узнает, что функция существует. Ему не нужно знать, что делает функция, достаточно знать, что она выглядит как void Frobnicate(int, float) или какова ее сигнатура.

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

person jalf    schedule 16.03.2009

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

Когда export для шаблонов будет больше поддерживаться, это будет не так, но сейчас его все еще вряд ли можно использовать.

person vava    schedule 16.03.2009
comment
Я не рекомендую использовать export. Согласно parashift.com/c++-faq-lite/templates. html#faq-35.14, он был исключен из стандарта C++0x. - person uckelman; 29.09.2010

Является ли их какой-либо шаблон поддержки компилятора отдельной компиляцией?

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

person baye    schedule 16.03.2009
comment
Комо я верю. И современная версия MSVC может, но я сам не проверял. - person vava; 16.03.2009
comment
Последний VS2008 еще не поддерживает ключевое слово экспорта. кажется, ребята из MS зарезервировали это ключевое слово для будущей поддержки: предупреждение C4237: ключевое слово «экспорт» еще не поддерживается, но зарезервировано для использования в будущем - person baye; 16.03.2009