Проблема в том, что компилятор не знает, какие версии вашего шаблона нужно создать. Когда вы перемещаете реализацию своей функции в x.cpp, она находится в другом модуле перевода, чем main.cpp, и main.cpp не может ссылаться на конкретный экземпляр, потому что он не существует в этом контексте. Это хорошо известная проблема с шаблонами C ++. Есть несколько решений:
1) Просто поместите определения прямо в файл .h, как вы делали раньше. Это имеет свои плюсы и минусы, в том числе решение проблемы (за), возможно, делает код менее читаемым и на некоторых компиляторах труднее отлаживать (con) и, возможно, увеличивает раздувание кода (con).
2) Поместите реализацию в x.cpp, а #include "x.cpp"
из x.h
. Если это кажется странным и неправильным, просто имейте в виду, что #include
делает только чтение указанного файла и компилирует его , как если бы этот файл был частью x.cpp
Другими словами, это делает именно то, что Решение № 1 делает выше, но оно хранит их в отдельных физических файлах. При выполнении подобных действий крайне важно, чтобы вы не пытались скомпилировать файл #include
d самостоятельно. По этой причине я обычно даю файлам такого типа расширение hpp
, чтобы отличать их от файлов h
и cpp
.
Файл: dumper2.h
#include <iostream>
#include <string>
#include <vector>
void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);
#include "dumper2.hpp"
Файл: dumper2.hpp
template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;
vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}
3) Поскольку проблема заключается в том, что конкретное создание экземпляра dumpVector
неизвестно единице перевода, которая пытается его использовать, вы можете принудительно вызвать конкретное создание этого экземпляра в той же единице перевода, в которой определен шаблон , Просто добавив это: template void dumpVector<int>(std::vector<int> v, std::string sep);
... в файл, где определен шаблон. Для этого вам больше не нужно #include
файл hpp
из файла h
:
Файл: dumper2.h
#include <iostream>
#include <string>
#include <vector>
void test();
template <class T> void dumpVector( std::vector<T> v,std::string sep);
Файл: dumper2.cpp
template <class T> void dumpVector(std::vector<T> v, std::string sep) {
typename std::vector<T>::iterator vi;
vi = v.begin();
std::cout << *vi;
vi++;
for (;vi<v.end();vi++) {
std::cout << sep << *vi ;
}
std::cout << "\n";
return;
}
template void dumpVector<int>(std::vector<int> v, std::string sep);
Кстати, и в целом, ваша шаблонная функция принимает vector
по значению . Вы можете не захотеть делать это и передавать его по ссылке или по указателю или, что еще лучше, вместо этого передавать итераторы, чтобы избежать создания временного и копирования всего вектора.