Russian Qt Forum

Программирование => С/C++ => Тема начата: Vamireh от Апрель 27, 2013, 18:45



Название: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: 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


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Vamireh от Апрель 27, 2013, 18:46
В смысле не при запуске, а при использовании этого метода ругается при компиляции


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: alex312 от Апрель 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;
}
 


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: sergek от Апрель 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));
}


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Igors от Апрель 28, 2013, 12:15
Проще всего собрать тела в cpp файл, но не включать его в проект а добавить инклудом в конец h файла

Код
C++ (Qt)
// Array3.h
...
#include "Array3.cpp"  


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: KrupaKarlo от Май 13, 2013, 14:54
в книге Дэвид Вандевурд, Николай М. Джосаттис. Шаблоны C++. Справочник разработчика. есть по этой теме глава. Там предложены разные варианты


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Akon от Май 14, 2013, 09:31
Цитировать
Чтобы определение не включать в код, где используется шаблон, надо использовать ключевое слово export.
Ерунда.

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

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

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


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Igors от Май 14, 2013, 09:48
Если под использованием понимается инстанцирование шаблона, то (только подумайте) как компилятор это сделает, не имея определения шаблона.
Хмм... каким образом? Можно пример? Спасибо


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: sergek от Май 14, 2013, 19:30
Цитировать
Чтобы определение не включать в код, где используется шаблон, надо использовать ключевое слово export.
Ерунда.
Сильно. Не все компиляторы это поддерживают, это да. В mingw 4.7 и C++Builder 6.0 это получилось. Страуструп в своем специальном издании (2010 г.) указывал, что виндовые компиляторы Microsoft, к примеру, не поддерживают.


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Akon от Май 15, 2013, 08:50
Цитировать
Хмм... каким образом? Можно пример? Спасибо

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

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

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


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Igors от Май 15, 2013, 11:39
В строке foo() происходит инстанцирование шаблона; компилятору должно быть известно тело функции (определение шаблона) - может тип T не имеет default construction.Nj
То да, но ведь Вы утверждали обратное

Если под использованием понимается инстанцирование шаблона, то (только подумайте) как компилятор это сделает, не имея определения шаблона.
Или Вы имели ввиду ошибки линковки? В общем, я Вас не понял  :)


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Akon от Май 15, 2013, 12:22
Человек выше в теме написал, что, типо, сделай extern и тело шаблона не нужно, т.е. как внешняя функция - достаточно только прототипа. В случае с шаблоном только прототипа недостаточно.



Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: sergek от Май 15, 2013, 19:05
Признаю, насчет поддержки export компиляторами mingw и Builder я погорячился... :( Для них объявление и определение должны находиться в одной единице трансляции.


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Fat-Zer от Май 15, 2013, 22:58
Проще всего собрать тела в cpp файл, но не включать его в проект а добавить инклудом в конец h файла
ещё 5 копеек: хороший приём ИМХО давать таким файлам альтернативные расширения, например .cc или .cxx.

sergek, Akon, не видел ни один компилятор, который поддерживал бы export... хотя в книжках пишут примеры именно в таком виде, как описал sergek, но в стандарте о слове export всего пара куцых абзацев и один пример «как неправильно делать»...
с другой стороны непонятно, как компиляторы в принципе могут реализовать такое поведение, так что это наводит на мысль, что многие книжки врут...


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: Akon от Май 16, 2013, 07:15
Чтобы реализовать export нужно сделать примерно следующее:
- в каждой точке инстанцирования запомнить что за шаблон и с какими параметрами инстанцируется,
- не включать код шаблона в эту единицу трансляции, а делать вызовы внешними,
- создать специальную единицу трансляции (или несколько единиц), в которой будет код инстанцированных шаблонов.

Но в точках инстанцирования определение шаблона должно быть доступно с тем, чтобы проверить корректность шаблона для данных аргументов (пример я привел выше).


Название: Re: Как вынести реализацию метода из хидера в cpp (Шаблоны)
Отправлено: sergek от Май 16, 2013, 20:50
sergek, Akon, не видел ни один компилятор, который поддерживал бы export...
В книге, о которой говорил KrupaKarlo, упоминается компилятор компании Edison Design Group, Inc. (EDG). Не думал, что все так запущено...