Почему при использовании шаблонов я получаю ошибки "неразрешенных внешних символов"?

Когда я пишу код С++ для класса с использованием шаблонов и разделяю код между исходным (CPP) файлом и файлом заголовка (H), я получаю много ошибок "неразрешенных внешних символов", когда дело доходит до ссылки на окончательный исполняемый файл, несмотря на то, что объектный файл правильно построен и включен в ссылку. Что происходит здесь, и как я могу это исправить?

Ответ 1

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

В результате всего этого компилятор просто предполагает, что он определен в другом месте и только вставляет вызов функции templated. Когда дело доходит до компиляции исходного файла шаблона, тип конкретного шаблона, который используется в исходном коде программы, не используется там, поэтому он все равно не будет генерировать код, необходимый для этой функции. Это приводит к неразрешенному внешнему символу.

Доступны следующие решения:

  • включить полное определение функция-член в файл заголовка шаблона и не иметь исходный файл для шаблона,
  • определить все функции-члены в исходный файл шаблона как "inline", или
  • определить участника функции в источнике шаблона с ключевым словом "экспорт". К сожалению, это не поддерживается много компиляторов. (Обновление: это было удалено из стандартного как С++ 11.)

Оба 1 и 2 в основном решают проблему, предоставляя компилятору доступ ко всему коду для шаблонной функции, когда он пытается построить типизированную функцию в исходном коде программы.

Ответ 2

Другой вариант - поместить код в файл cpp и в тот же файл cpp добавить явные экземпляры шаблона с типами, которые вы ожидаете использовать. Это полезно, если вы знаете, что собираетесь использовать его только для нескольких типов, которые вы знаете заранее.

Ответ 3

Для каждого файла, который содержит файл .h, вы должны вставлять обе строки:

#include "MyfileWithTemplatesDeclaration.h"
#include "MyfileWithTemplatesDefinition.cpp"

Пример

#include "list.h"
    #include "list.cpp" //<---for to fix bug link err 2019



    int main(int argc, _TCHAR* argv[])
    {
        list<int> my_list;
        my_list.add_end(3);
    .
    .
    } 

Кроме того, вы не забудете разместить свой класс объявлений среди констант в сантинеле

#ifndef LIST_H
#define LIST_H
#include <iostream>
.
.
template <class T>
class list
{
private:
    int m_size,
        m_count_nodes;
    T m_line;
    node<T> *m_head;
public:
    list(void);
    ~list(void);
    void add_end(T);
    void print();
};
#endif