Шаблонный класс – Символы, не найденные, [копируют]

7
задан Community 23 May 2017 в 12:25
поделиться

2 ответа

Подробное объяснение доступно на http://www.parashift.com/c++-faq-lite/templates.html

[35.12] Почему я не могу отделить определение моего класса шаблонов от его объявления и поместить его в файл .cpp?

Если все, что вам нужно знать, это как исправить эту ситуацию, прочтите следующие два FAQ. Но для того, чтобы понять, почему все обстоит именно так, сначала примите следующие факты:

  1. Шаблон - это не класс или функция. Шаблон - это «шаблон», который компилятор использует для создания семейства классов или функций.
  2. Чтобы компилятор сгенерировал код, он должен видеть как определение шаблона (а не только объявление), так и конкретные типы / все, что используется для «заполнения» шаблона.Например, если вы пытаетесь использовать Foo, компилятор должен видеть и шаблон Foo, и тот факт, что вы пытаетесь создать конкретный Foo.
  3. Ваш компилятор, вероятно, не запоминает детали одного файла .cpp во время компиляции другого файла .cpp. Может, но большинство нет, и если вы читаете этот FAQ, почти наверняка нет. Кстати, это называется «модель отдельной компиляции».

Теперь, основываясь на этих фактах, вот пример, который показывает, почему все так, как есть. Предположим, у вас есть шаблон Foo, определенный следующим образом:

template<typename T>
class Foo {
 public:
   Foo();
   void someMethod(T x);  
 private:
   T x;
};

Наряду с аналогичными определениями для функций-членов:

 template<typename T>
 Foo<T>::Foo()
 {
   ...
 }

 template<typename T>
 void Foo<T>::someMethod(T x)
 {
   ...
 }

Теперь предположим, что у вас есть некоторый код в файле Bar.cpp, который использует Foo:

// Bar.cpp

void blah_blah_blah()
 {
   ...
   Foo<int> f;
   f.someMethod(5);
   ...
 }

] Очевидно, что кто-то где-то должен будет использовать "шаблон" для определения конструктора и для определения someMethod () и создавать их экземпляры, когда T на самом деле int. Но если вы поместите определение конструктора и someMethod () в файл Foo.cpp, компилятор увидит код шаблона при компиляции Foo.cpp и Foo при компиляции Bar.cpp, но никогда не будет время, когда он увидел и код шаблона, и Foo. Таким образом, по правилу №2, приведенному выше, он никогда не сможет сгенерировать код для Foo :: someMethod ().

Примечание для экспертов: очевидно, что я сделал несколько упрощений выше. Это было сделано намеренно, поэтому, пожалуйста, не жалуйтесь слишком громко. Если вы знаете разницу между файлом.cpp файл и модуль компиляции, разница между шаблоном класса и классом шаблона, и тот факт, что шаблоны на самом деле не просто прославленные макросы, тогда не жалуйтесь: этот конкретный вопрос / ответ не был нацелен на вас, чтобы начать с участием. Я упростил вещи, чтобы новички «поняли», даже если это оскорбит некоторых экспертов.

[35.13] Как я могу избежать ошибок компоновщика с моими функциями шаблона?

Сообщите вашему компилятору C ++, какие экземпляры нужно создать, пока он компилирует файл .cpp вашей функции шаблона.

В качестве примера рассмотрим заголовочный файл foo.h, который содержит следующее объявление функции шаблона:

// Файл "foo.h"

 template<typename T>
 extern void foo();

Теперь предположим, что файл foo.cpp действительно определяет эту функцию шаблона:

// Файл "foo.cpp"

 #include <iostream>
 #include "foo.h"

 template<typename T>
 void foo()
 {
   std::cout << "Here I am!\n";
 }

Предположим, что файл main.cpp использует эту функцию шаблона, вызывая foo ():

// Файл "main.cpp"

 #include "foo.h"

 int main()
 {
   foo<int>();
   ...
 }

Если вы компилируете и (пытаетесь) связать эти два файла .cpp, большинство компиляторов будут генерировать ошибки компоновщика. Для этого есть три решения. Первое решение - физически переместить определение функции шаблона в файл .h, даже если это не встроенная функция. Это решение может (или не может!) Вызвать значительное раздувание кода, а это означает, что размер вашего исполняемого файла может резко увеличиться (или, если ваш компилятор достаточно умен, может и нет; попробуйте и убедитесь).

Другое решение - оставить определение функции шаблона в файле .cpp и просто добавить шаблон строки void foo (); в этот файл:

// Файл "foo.cpp"

 #include <iostream>
 #include "foo.h"

 template<typename T> void foo()
 {
   std::cout << "Here I am!\n";
 }

 template void foo<int>();

Если вы не можете изменить foo.cpp, просто создайте новый файл .cpp, такой как foo-impl.cpp следующим образом:

// Файл "foo-impl.cpp"

 #include "foo.cpp"

 template void foo<int>();

Обратите внимание, что foo-impl.cpp # включает файл .cpp, а не файл .h.

11
ответ дан 7 December 2019 в 01:16
поделиться

Это потому что у меня есть отдельный заголовок и .cpp файл для Vector?

Да.

Как мне заставить мою главную функцию распознавать функции моего класса Vector?

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

По сути, определение шаблона должно быть доступно в main.cpp, чтобы он инстанцировал шаблон с аргументами, которые вы используете (double, в данном случае).

1
ответ дан 7 December 2019 в 01:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: