Подтвердить что ты не робот

Проблема с шаблоном вызывает ошибку компоновщика (С++)

У меня очень мало информации о том, что происходит с шаблонами С++, но я пытаюсь реализовать функцию, которая ищет вектор для элемента, удовлетворяющего заданному свойству (в этом случае поиск одного с указанным именем). Мое объявление в моем файле .h выглядит следующим образом:

template <typename T>
T* find_name(std::vector<T*> v, std::string name);

Когда я компилирую, я получаю эту ошибку компоновщика при вызове функции:

Error   1   error LNK2019: unresolved external symbol "class Item * __cdecl find_name<class Item>(class std::vector<class Item *,class std::allocator<class Item *> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" ([email protected]@@@@[email protected]@[email protected]@@[email protected]@@@[email protected]@@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z) referenced in function "public: class Item * __thiscall Place::get_item(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" ([email protected]@@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@@Z) place.obj   Program2

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

Также, связанный вопрос: есть ли способ сделать параметр шаблона так, чтобы он был подклассом определенного класса, то есть шаблона?

4b9b3361

Ответ 1

Вы должны иметь определения шаблонов на вызывающем сайте. Это означает, что нет файлов .cpp.

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

Шаблоны - это только резак для печенья, потому что они не знают, какой тип файлов cookie они есть. Он сообщает компилятору, как делать функцию при задании типа, но сам по себе он не может использоваться, потому что не существует конкретного типа. Вы не можете готовить резак для печенья. Только когда у вас есть вкусное тесто для печенья (т.е. С учетом компилятора тесто [тип]), вы можете отрезать куки и приготовить его.

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

Ответ 2

Вероятно, вы страдаете от отсутствия действительного экземпляра. Если вы поместите определение вашего шаблона в отдельный .cpp файл, когда компилятор компилирует этот файл, он может не знать, какие экземпляры вам нужны. И наоборот, на сайтах вызовов, которые будут создавать правильную версию функции шаблона, если определение тела функции недоступно, компилятору не будет предоставлена ​​информация для создания необходимых специализаций.

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

например. в файле заголовка:

template <typename T>
inline T* find_name(std::vector<T*> v, std::string name)
{
    // ...
}

или явно создать экземпляр шаблона в .cpp, где вы определили шаблон.

например. в исходном файле (возможно, потребуется #include файл, который определяет Item):

template <typename T>
T* find_name(std::vector<T*> v, std::string name)
{
    // ...
}

template Item* find_name<Item>(std::vector<Item*> v, std::string name);

Ответ 3

Ответы здесь замечательные.

Я просто добавлю, что это часто почему в дополнение к файлам .h и .cpp в проекте. Вы часто найдете файлы .inl. Определения шаблонов войдут в файл .inl.

Эти файлы .inl означают inline и обычно будут включены в файл .h с одним и тем же именем в нижней части файла после всех объявлений заголовков. Это фактически делает их частью файла заголовка, но отделяет объявления от любых определений.

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

Ответ 4

Наткнулся на ту же проблему и нашел это, в котором говорится о трех обходных решениях: http://www.codeproject.com/Articles/48575/How-to-define-a-template-class-in-a-h-file-and-imp

Среди них простой, когда вы создаете метод "dummy" в файле .cpp, который вызывает функцию template/class с разными типами. Вставка из ссылки:

// No need to call this TemporaryFunction() function, it just to avoid link error.
void TemporaryFunction ()
{
    TestTemp<int> TempObj;
    TestTemp<float> TempObj2;
}

Ответ 5

Вы указали определение функции шаблона в файле cpp? Затем переместите его в заголовок и введите его.

Ответ 6

Я только заметил, что у вас есть второй вопрос, который кажется без ответа:

Есть ли способ сделать параметр шаблона так, чтобы он был подклассом определенного класса, т.е. шаблона?

Это возможно. Например, см. is_base_of в Boost.TypeTraits.

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

template<class T>
void foo(const T& t)
{
    if (t.foo()){
       t.bar("blah");
    }
}

Говоря, что T наследует что-то вроде:

class HasFooAndBar
{
public:
  void foo()const;
  void bar(const char*)const;
};

ничего не приносит, потому что экземпляр функции будет терпеть неудачу, если тип не поддерживает операции. Более того, он бесполезно ограничивает применимость foo(). Фактически, любые требования заключаются в том, что t.foo() and t.bar(const char*) являются допустимыми выражениями для const T. Например, этот тип не наследует от HasFooAndBar и по-прежнему является допустимым параметром foo():

struct DifferentFromHasFooAndBar
{
  bool foo()const;
  std::string bar(const std::string&)const;
};