Страница 1 из 2

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

Добавлено: 01 мар 2010, 12:56
Dragon
Есть дружественная функция в шаблоне класса:

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

//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'
А также предупреждение, что используется нешаблонная дружественная функция.

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

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

Добавлено: 01 мар 2010, 17:20
BulldozerBSG
А как это вы описали функцию шаблона в CPP, при чем там где шаблон не используется O_O

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

Добавлено: 01 мар 2010, 17:45
Dragon
Возможно более полный вариант класса надо было представить:

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

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

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

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

Ешё я вижу грубую ошибку #include "list.cpp". Так делать нельзя. Если такое приходится писать для того, чтобы всё заработало, то знай сразу, что используешь неправильный подход.

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

Добавлено: 01 мар 2010, 18:07
Dragon
Хм. Т.е. сразу давать определение перегруженному оператору?
Ешё я вижу грубую ошибку #include "list.cpp". Так делать нельзя. Если такое приходится писать для того, чтобы всё заработало, то знай сразу, что используешь неправильный подход.
Но без #include "list.cpp" будет 'undefined reference' в int main(). Иначе же шаблон не разделить (как обычный класс) на файл интерфейса и реализации.
Какие есть другие варианты?

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

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

Существует ещё разделение кода теплейтов на h и hxx файлы, но это лишь более строгая нотация. Файл hxx всё равно остаётся хедер-файлом по своей сути.

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

Добавлено: 01 мар 2010, 19:00
BulldozerBSG
Я бы сказал проще. Шаблоны ведут себя как макросы в какой то степени. От сюда все вытекающие...

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

Добавлено: 01 мар 2010, 20:08
Romeo
Сорри, но я не вижу ни одной характерной черты макроса. Хоть одну сможешь привести? Честное слово, долго пытался разглядеть.

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

Добавлено: 02 мар 2010, 10:17
Dragon
А как быть с принципом "черного ящика"? Или на шаблонные классы и шаблоны вообще это не распространяется?

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

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