Шаблоны и дружественные функции.

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Dragon
Сообщения: 99
Зарегистрирован: 01 окт 2009, 11:21
Откуда: Odessa
Контактная информация:

Есть дружественная функция в шаблоне класса:

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

//list.h
template<typename ItemType>
    class List
    {
        public:
            friend ostream& operator <<(ostream& outs, const List<ItemType>& the_list);
     }


//list.cpp
template<typename ItemType>
    ostream& operator <<(ostream& outs, const List<ItemType>& the_list)
    {
        for(int i = 0; i < the_list.current_length; i++)
        {
            outs << the_list.item[i] << endl;
        }
        return outs;
    }

//list_demo.cpp
#include <iostream>
#include "list.h"
#include "list.cpp"

using namespace std;
using namespace listsavitch;

int main()
{
    List<int> first_list(2);
    first_list.add(1);
    first_list.add(2);
    cout << "first_list = \n"
         << first_list;

    return 0;
}
Компилятор выдает ошибку:
undefined reference to `operator<< bla-bla-bla'
А также предупреждение, что используется нешаблонная дружественная функция.

Проблему решил расписав определение перегруженного оператора в интерфейсе класса. НО как заставить компилятор понимать изначальный вариант, что там дружественная функция шаблонная???
BulldozerBSG
Сообщения: 270
Зарегистрирован: 09 янв 2010, 04:14
Контактная информация:

А как это вы описали функцию шаблона в CPP, при чем там где шаблон не используется O_O
Dragon
Сообщения: 99
Зарегистрирован: 01 окт 2009, 11:21
Откуда: Odessa
Контактная информация:

Возможно более полный вариант класса надо было представить:

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

//list.h
#ifndef LIST_H
#define LIST_H
#include <iostream>
using namespace std;

namespace listsavitch
{
    template<typename ItemType>
    class List
    {.....
#endif

//list.cpp
#ifndef LIST_CPP
#define LIST_CPP
#include <iostream>
#include <cstdlib>
#include "list.h"
using namespace std;

namespace listsavitch
{...

#endif
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Так, как ты пытаешь сделать, сделать не получится. Для того, что компилятор сгенерировал темплейт оператора, он должен видеть этот темплейт в том месте, где его используют.

Ешё я вижу грубую ошибку #include "list.cpp". Так делать нельзя. Если такое приходится писать для того, чтобы всё заработало, то знай сразу, что используешь неправильный подход.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Dragon
Сообщения: 99
Зарегистрирован: 01 окт 2009, 11:21
Откуда: Odessa
Контактная информация:

Хм. Т.е. сразу давать определение перегруженному оператору?
Ешё я вижу грубую ошибку #include "list.cpp". Так делать нельзя. Если такое приходится писать для того, чтобы всё заработало, то знай сразу, что используешь неправильный подход.
Но без #include "list.cpp" будет 'undefined reference' в int main(). Иначе же шаблон не разделить (как обычный класс) на файл интерфейса и реализации.
Какие есть другие варианты?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Это особенность шаблонов. Других вариантов нету. Для того, что компилятор сгенерировал тело оператора для конкретного типа, темплейт-оператор должнен быть виден в том месте, где происходит его инстанцирование. Таким образом он обязан быть включённым в хедер.

Существует ещё разделение кода теплейтов на h и hxx файлы, но это лишь более строгая нотация. Файл hxx всё равно остаётся хедер-файлом по своей сути.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
BulldozerBSG
Сообщения: 270
Зарегистрирован: 09 янв 2010, 04:14
Контактная информация:

Я бы сказал проще. Шаблоны ведут себя как макросы в какой то степени. От сюда все вытекающие...
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Сорри, но я не вижу ни одной характерной черты макроса. Хоть одну сможешь привести? Честное слово, долго пытался разглядеть.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Dragon
Сообщения: 99
Зарегистрирован: 01 окт 2009, 11:21
Откуда: Odessa
Контактная информация:

А как быть с принципом "черного ящика"? Или на шаблонные классы и шаблоны вообще это не распространяется?
BulldozerBSG
Сообщения: 270
Зарегистрирован: 09 янв 2010, 04:14
Контактная информация:

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