Russian Qt Forum
Май 04, 2024, 17:53 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Как вынести реализацию метода из хидера в cpp (Шаблоны)  (Прочитано 10166 раз)
Vamireh
Гость
« : Апрель 27, 2013, 18:45 »

Вопрос может и тупой, но...

Код:
template <typename T> class Array3
{
    template <class>
    friend class Array3;

private:
    T d[3];

public:
    Array3<T>(const T x, const T y, const T z)
    {
        this->d[0] = x; this->d[1] = y; this->d[2] = z;
    }

    inline const T operator [](const int i) const
    {
        return this->d[i];
    }

    template <typename TT> inline Array3<T> operator *(Array3<TT> const &a)
    {
        return Array3<T>(this->d[0] * a[0], this->d[1] * a[1], this->d[2] * a[2]);
    }

    inline Array3<T> & operator =(const T &a)
    {
        return (*this = Array3<T>(a, a, a));
    }
};

Есть такой класс. Как вынести реализацию оператора умножения в cpp? Вот так компилируется:
Код:
template <class T>
template <class TT>
Array3<T> Array3<T>::operator *(Array3<TT> const &a)
{
    return Array3<T>(this->d[0] * a[0], this->d[1] * a[1], this->d[2] * a[2]);
}

Но при запуске пишет: error: undefined reference to `Array3<double> Array3<double>::operator*<double>(Array3<double> const&)'
Может я страшно туплю, но помогите, пожалуйста.
Если что, компилятор MinGW
Записан
Vamireh
Гость
« Ответ #1 : Апрель 27, 2013, 18:46 »

В смысле не при запуске, а при использовании этого метода ругается при компиляции
Записан
alex312
Хакер
*****
Offline Offline

Сообщений: 606



Просмотр профиля
« Ответ #2 : Апрель 27, 2013, 19:16 »

как вариант:
Код
C++ (Qt)
template <typename T>
class Array3
{
   template <class>
   friend class Array3;
 
   template<class TT, class TTT>
   friend Array3<TT>& operator*(Array3<TT>& , const Array3<TTT>& );
 
private:
   T d[3];
 
public:
   Array3<T>(const T x = T(), const T y = T(), const T z = T())
   {
       this->d[0] = x; this->d[1] = y; this->d[2] = z;
   }
 
   inline const T operator [](const int i) const
   {
       return this->d[i];
   }
 
//    template <typename TT> inline Array3<T> operator *(Array3<TT> const &a)
//    {
//        return Array3<T>(this->d[0] * a[0], this->d[1] * a[1], this->d[2] * a[2]);
//    }
 
   inline Array3<T> & operator =(const T &a)
   {
       return (*this = Array3<T>(a, a, a));
   }
};
 
template<class T, class TT>
Array3<T>& operator*(Array3<T>& t, const Array3<TT>& tt )
{
   t.d[0] = t[0]*tt[0];
   t.d[1] = t[1]*tt[1];
   t.d[2] = t[2]*tt[2];
   return t;
}
 
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 870


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #3 : Апрель 27, 2013, 22:46 »

Вопрос может и тупой, но...
Чтобы определение не включать в код, где используется шаблон, надо использовать ключевое слово export. Примерно так:
Объявление в .h:
Код:
template <typename T> class Array3
{
    template <class>
    friend class Array3;

private:
    T d[3];

public:
    Array3<T>(const T x, const T y, const T z);
    inline const T operator [](const int i) const;
    template <typename TT> inline Array3<T> operator *(Array3<TT> const &a);
    inline Array3<T> & operator =(const T &a);
};
Определение в .cpp:
Код:
export template <typename T> Array3<T>::Array3(const T x, const T y, const T z)
{
    this->d[0] = x; this->d[1] = y; this->d[2] = z;
}
export template <typename T> const T Array3<T>::operator [](const int i) const
{
    return this->d[i];
}

export template <typename T>
       template <typename TT> inline Array3<T> Array3<T>::operator *(Array3<TT> const &a)
{
    return Array3<T>(this->d[0] * a[0], this->d[1] * a[1], this->d[2] * a[2]);
}

export template <typename T> inline Array3<T> & Array3<T>::operator =(const T &a)
{
    return (*this = Array3<T>(a, a, a));
}
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Апрель 28, 2013, 12:15 »

Проще всего собрать тела в cpp файл, но не включать его в проект а добавить инклудом в конец h файла

Код
C++ (Qt)
// Array3.h
...
#include "Array3.cpp"  
Записан
KrupaKarlo
Гость
« Ответ #5 : Май 13, 2013, 14:54 »

в книге Дэвид Вандевурд, Николай М. Джосаттис. Шаблоны C++. Справочник разработчика. есть по этой теме глава. Там предложены разные варианты
Записан
Akon
Гость
« Ответ #6 : Май 14, 2013, 09:31 »

Цитировать
Чтобы определение не включать в код, где используется шаблон, надо использовать ключевое слово export.
Ерунда.

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

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

Если выносится реализация шаблона, обычно, ее делают в отдельном файле *.inl, что дает свободу последующего подключения либо к *.cpp, либо к *.h файлам, использующим шаблон.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Май 14, 2013, 09:48 »

Если под использованием понимается инстанцирование шаблона, то (только подумайте) как компилятор это сделает, не имея определения шаблона.
Хмм... каким образом? Можно пример? Спасибо
Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 870


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #8 : Май 14, 2013, 19:30 »

Цитировать
Чтобы определение не включать в код, где используется шаблон, надо использовать ключевое слово export.
Ерунда.
Сильно. Не все компиляторы это поддерживают, это да. В mingw 4.7 и C++Builder 6.0 это получилось. Страуструп в своем специальном издании (2010 г.) указывал, что виндовые компиляторы Microsoft, к примеру, не поддерживают.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Akon
Гость
« Ответ #9 : Май 15, 2013, 08:50 »

Цитировать
Хмм... каким образом? Можно пример? Спасибо

К примеру, шаблон функции:
Код:
template <typename T> 
void foo()
{
   T t;
}

Далее где-то использование:
foo();

В строке foo() происходит инстанцирование шаблона; компилятору должно быть известно тело функции (определение шаблона) - может тип T не имеет default construction.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Май 15, 2013, 11:39 »

В строке foo() происходит инстанцирование шаблона; компилятору должно быть известно тело функции (определение шаблона) - может тип T не имеет default construction.Nj
То да, но ведь Вы утверждали обратное

Если под использованием понимается инстанцирование шаблона, то (только подумайте) как компилятор это сделает, не имея определения шаблона.
Или Вы имели ввиду ошибки линковки? В общем, я Вас не понял  Улыбающийся
Записан
Akon
Гость
« Ответ #11 : Май 15, 2013, 12:22 »

Человек выше в теме написал, что, типо, сделай extern и тело шаблона не нужно, т.е. как внешняя функция - достаточно только прототипа. В случае с шаблоном только прототипа недостаточно.

Записан
sergek
Гипер активный житель
*****
Offline Offline

Сообщений: 870


Мы должны приносить пользу людям.


Просмотр профиля
« Ответ #12 : Май 15, 2013, 19:05 »

Признаю, насчет поддержки export компиляторами mingw и Builder я погорячился... Грустный Для них объявление и определение должны находиться в одной единице трансляции.
Записан

Qt 5.13.0 Qt Creator 5.0.1
Win10, Ubuntu 20.04
Fat-Zer
Гость
« Ответ #13 : Май 15, 2013, 22:58 »

Проще всего собрать тела в cpp файл, но не включать его в проект а добавить инклудом в конец h файла
ещё 5 копеек: хороший приём ИМХО давать таким файлам альтернативные расширения, например .cc или .cxx.

sergek, Akon, не видел ни один компилятор, который поддерживал бы export... хотя в книжках пишут примеры именно в таком виде, как описал sergek, но в стандарте о слове export всего пара куцых абзацев и один пример «как неправильно делать»...
с другой стороны непонятно, как компиляторы в принципе могут реализовать такое поведение, так что это наводит на мысль, что многие книжки врут...
Записан
Akon
Гость
« Ответ #14 : Май 16, 2013, 07:15 »

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

Но в точках инстанцирования определение шаблона должно быть доступно с тем, чтобы проверить корректность шаблона для данных аргументов (пример я привел выше).
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.092 секунд. Запросов: 22.